Ronald G. Minnich (rminnich@gmail.com) just uploaded a new patch set to gerrit, which you can find at http://review.coreboot.org/1679
-gerrit
commit b642d2f789655830707064c8359552255552fe8e Author: David Hendricks dhendrix@chromium.org Date: Tue Oct 30 20:47:51 2012 -0700
WIP: initial Snow board (ARM/Exynos 5250) support
This pulls in lots of sources from U-Boot for the Snow board, which is used in Google's Chromebook based on the Exynos 5250 SoC from Samsung. This patch will likely be broken down significantly, I'm just uploading it as a draft for convenience. It does not compile and is nowhere near complete.
When compiling in the ChromeOS SDK chroot environment, use "CROSS_COMPILE=armv7a-cros-linux-gnueabi-". For now this patch also includes a config.snow file which sets the Kconfig options for Exynos (cp config.snow .config && make oldconfig && make).
Overview of the code structure: - src/arch/armv7 - Common ARMv7 architecture files. This includes common headers and libraries.
- src/cpu/samsung - Samsung SoC files, including Exynos5 (a Cortex-A15 implementation). Since this is an SoC we'll forego the x86-style {north,south}bridge and cpu distinction. We may try to split some stuff out before the final version if prudent.
- src/mainboard/google/snow - Mainboard directory (public name is "snow"). There are references to the Samsung SMDK5250 which is the development kit. Maybe we can add that as a separate board along with the Samsung Arndale (www.arndaleboard.org).
TODO items: - The difference between romstage and ramstage is confusing (in context of this code). board_init_f() seems like it should be done in ramstage, since caches should be set up when start.S calls it. - Remove superfluous Linux code - Split out changes to console (e.g. src/console/Kconfig) - Incorporate dianders' DRAM fix from u-boot - Make sure CBFS works... - Do something about device tree / ACPI - (Re)move config.snow - Remove unneeded S5P stuff
Change-Id: Ic3ed72c88948af0ecb37f5ea9f2056451738146a Signed-off-by: David Hendricks dhendrix@chromium.org Signed-off-by: Stefan Reinauer reinauer@google.com --- Makefile | 4 +- config.snow | 323 ++++++ src/arch/armv7/Kconfig | 52 + src/arch/armv7/Makefile.inc | 324 ++++++ src/arch/armv7/boot/Makefile.inc | 13 + src/arch/armv7/boot/acpi.c | 791 +++++++++++++ src/arch/armv7/boot/acpigen.c | 729 ++++++++++++ src/arch/armv7/boot/boot.c | 189 ++++ src/arch/armv7/boot/coreboot_table.c | 711 ++++++++++++ src/arch/armv7/boot/multiboot.c | 77 ++ src/arch/armv7/boot/tables.c | 100 ++ src/arch/armv7/boot/wakeup.S | 94 ++ src/arch/armv7/bootblock_simple.c | 51 + src/arch/armv7/coreboot_ram.ld | 128 +++ src/arch/armv7/cpu.c | 101 ++ src/arch/armv7/include/arch/atomic.h | 111 ++ src/arch/armv7/include/arch/boot/boot.h | 8 + src/arch/armv7/include/arch/byteorder.h | 27 + src/arch/armv7/include/arch/coreboot_tables.h | 25 + src/arch/armv7/include/arch/cpu.h | 21 + src/arch/armv7/include/arch/gpio.h | 98 ++ src/arch/armv7/include/arch/hlt.h | 10 + src/arch/armv7/include/arch/io.h | 473 ++++++++ src/arch/armv7/include/arch/pci_ops.h | 19 + src/arch/armv7/include/arch/types.h | 53 + src/arch/armv7/include/armv7.h | 76 ++ src/arch/armv7/include/asm/bitops.h | 316 ++++++ src/arch/armv7/include/asm/bitsperlong.h | 28 + src/arch/armv7/include/asm/irqflags.h | 155 +++ src/arch/armv7/include/asm/memory.h | 300 +++++ src/arch/armv7/include/asm/posix_types.h | 77 ++ src/arch/armv7/include/asm/system.h | 62 + src/arch/armv7/include/asm/types.h | 16 + src/arch/armv7/include/assembler.h | 60 + src/arch/armv7/include/bootblock_common.h | 69 ++ src/arch/armv7/include/cache.h | 58 + src/arch/armv7/include/clocks.h | 44 + src/arch/armv7/include/common.h | 494 ++++++++ src/arch/armv7/include/div64.h | 233 ++++ src/arch/armv7/include/global_data.h | 108 ++ src/arch/armv7/include/hang.h | 20 + src/arch/armv7/include/mmio_conf.h | 6 + src/arch/armv7/include/ptrace.h | 30 + src/arch/armv7/include/smp/spinlock.h | 52 + src/arch/armv7/include/stdint.h | 81 ++ src/arch/armv7/include/system.h | 66 ++ src/arch/armv7/include/uapi/asm/hwcap.h | 29 + src/arch/armv7/include/uapi/asm/ptrace.h | 138 +++ src/arch/armv7/include/utils.h | 56 + src/arch/armv7/ldscript_failover.lb | 74 ++ src/arch/armv7/ldscript_fallback_cbfs.lb | 51 + src/arch/armv7/lib/Makefile.inc | 26 + src/arch/armv7/lib/Makefile.uboot | 95 ++ src/arch/armv7/lib/_divsi3.S | 142 +++ src/arch/armv7/lib/_udivsi3.S | 93 ++ src/arch/armv7/lib/_uldivmod.S | 157 +++ src/arch/armv7/lib/bootm.c | 405 +++++++ src/arch/armv7/lib/c_start.S | 9 + src/arch/armv7/lib/cache-cp15.c | 305 +++++ src/arch/armv7/lib/cache_v7.c | 427 +++++++ src/arch/armv7/lib/div.c | 5 + src/arch/armv7/lib/div0.c | 32 + src/arch/armv7/lib/div64.S | 208 ++++ src/arch/armv7/lib/eabi_compat.c | 33 + src/arch/armv7/lib/hang_spl.c | 16 + src/arch/armv7/lib/id.inc | 18 + src/arch/armv7/lib/id.lds | 6 + src/arch/armv7/lib/interrupts.c | 198 ++++ src/arch/armv7/lib/memcpy.S | 243 ++++ src/arch/armv7/lib/memset.S | 126 +++ src/arch/armv7/lib/reset.c | 53 + src/arch/armv7/lib/romstage_console.c | 75 ++ src/arch/armv7/lib/syslib.c | 70 ++ src/arch/armv7/romstage.ld | 119 ++ src/arch/armv7/start.S | 542 +++++++++ src/arch/x86/include/stddef.h | 24 - src/console/Kconfig | 24 +- src/cpu/Kconfig | 9 + src/cpu/Makefile.inc | 1 + src/cpu/samsung/Kconfig | 46 + src/cpu/samsung/Makefile.inc | 5 + src/cpu/samsung/exynos5-common/Makefile.inc | 2 + src/cpu/samsung/exynos5-common/soc.c | 30 + src/cpu/samsung/exynos5-common/spl_boot.c | 460 ++++++++ src/cpu/samsung/exynos5250/Kconfig | 28 + src/cpu/samsung/exynos5250/Makefile.inc | 32 + src/cpu/samsung/exynos5250/ace_sha.c | 118 ++ src/cpu/samsung/exynos5250/clock.c | 610 ++++++++++ src/cpu/samsung/exynos5250/clock_init.c | 1189 ++++++++++++++++++++ src/cpu/samsung/exynos5250/dmc_common.c | 200 ++++ src/cpu/samsung/exynos5250/dmc_init_ddr3.c | 249 ++++ src/cpu/samsung/exynos5250/exynos_cache.c | 90 ++ src/cpu/samsung/exynos5250/lowlevel_init.S | 32 + src/cpu/samsung/exynos5250/lowlevel_init_c.c | 120 ++ src/cpu/samsung/exynos5250/pinmux.c | 303 +++++ src/cpu/samsung/exynos5250/power.c | 202 ++++ src/cpu/samsung/exynos5250/sata.c | 431 +++++++ src/cpu/samsung/exynos5250/setup.h | 7 +- src/cpu/samsung/exynos5250/soc.c | 47 + src/cpu/samsung/exynos5250/spl.c | 41 + src/cpu/samsung/exynos5250/tzpc_init.c | 57 + src/cpu/samsung/exynos5250/uart.c | 235 ++++ src/cpu/samsung/s5p-common/Makefile.inc | 12 + src/cpu/samsung/s5p-common/Makefile.uboot | 49 + src/cpu/samsung/s5p-common/cpu_info.c | 128 +++ src/cpu/samsung/s5p-common/pwm.c | 205 ++++ src/cpu/samsung/s5p-common/s5p_gpio.c | 490 ++++++++ src/cpu/samsung/s5p-common/sromc.c | 49 + src/cpu/samsung/s5p-common/timer.c | 153 +++ src/cpu/samsung/s5p-common/wdt.c | 59 + src/drivers/Kconfig | 1 + src/drivers/Makefile.inc | 1 + src/drivers/maxim/Kconfig | 5 + src/drivers/maxim/Makefile.inc | 20 + src/drivers/maxim/max77686.c | 257 +++++ src/include/cbfs_core.h | 3 + src/include/compiler.h | 140 +++ src/include/cpu/samsung/exynos-common/adc.h | 42 + src/include/cpu/samsung/exynos-common/clk.h | 70 ++ src/include/cpu/samsung/exynos-common/cpu.h | 99 ++ .../cpu/samsung/exynos-common/exynos5-common.h | 224 ++++ src/include/cpu/samsung/exynos-common/gpio.h | 73 ++ src/include/cpu/samsung/exynos-common/mmc.h | 77 ++ src/include/cpu/samsung/exynos-common/mshc.h | 170 +++ src/include/cpu/samsung/exynos-common/pwm.h | 68 ++ src/include/cpu/samsung/exynos-common/spi.h | 89 ++ src/include/cpu/samsung/exynos-common/spl.h | 94 ++ src/include/cpu/samsung/exynos-common/sromc.h | 69 ++ src/include/cpu/samsung/exynos-common/sys_proto.h | 32 + src/include/cpu/samsung/exynos-common/uart.h | 55 + src/include/cpu/samsung/exynos-common/watchdog.h | 57 + src/include/cpu/samsung/exynos5250/ace_sfr.h | 310 +++++ src/include/cpu/samsung/exynos5250/ace_sha.h | 41 + src/include/cpu/samsung/exynos5250/adc.h | 27 + src/include/cpu/samsung/exynos5250/clk.h | 586 ++++++++++ src/include/cpu/samsung/exynos5250/cpu.h | 134 +++ src/include/cpu/samsung/exynos5250/dmc.h | 211 ++++ src/include/cpu/samsung/exynos5250/dsim.h | 108 ++ src/include/cpu/samsung/exynos5250/ehci-s5p.h | 66 ++ .../cpu/samsung/exynos5250/exynos-cpufreq.h | 54 + src/include/cpu/samsung/exynos5250/exynos-tmu.h | 82 ++ src/include/cpu/samsung/exynos5250/fet.h | 25 + src/include/cpu/samsung/exynos5250/fimd.h | 137 +++ src/include/cpu/samsung/exynos5250/gpio.h | 482 ++++++++ src/include/cpu/samsung/exynos5250/i2s-regs.h | 146 +++ src/include/cpu/samsung/exynos5250/mmc.h | 27 + src/include/cpu/samsung/exynos5250/mshc.h | 31 + src/include/cpu/samsung/exynos5250/periph.h | 71 ++ src/include/cpu/samsung/exynos5250/pinmux.h | 59 + src/include/cpu/samsung/exynos5250/power.h | 89 ++ src/include/cpu/samsung/exynos5250/pwm.h | 27 + src/include/cpu/samsung/exynos5250/s5p-dp.h | 513 +++++++++ src/include/cpu/samsung/exynos5250/sata.h | 27 + src/include/cpu/samsung/exynos5250/spi.h | 89 ++ src/include/cpu/samsung/exynos5250/sys_proto.h | 27 + src/include/cpu/samsung/exynos5250/sysreg.h | 36 + src/include/cpu/samsung/exynos5250/tzpc.h | 52 + src/include/cpu/samsung/exynos5250/uart.h | 71 ++ src/include/cpu/samsung/exynos5250/watchdog.h | 27 + src/include/device/i2c.h | 279 +++++ src/include/device/power/max77686.h | 134 +++ src/include/stddef.h | 24 + src/include/uart.h | 33 + src/lib/Makefile.inc | 2 +- src/mainboard/Kconfig | 16 + src/mainboard/google/Kconfig | 17 + src/mainboard/google/snow/Kconfig | 162 +++ src/mainboard/google/snow/Makefile.inc | 36 + src/mainboard/google/snow/board.h | 33 + src/mainboard/google/snow/devicetree.cb | 7 + src/mainboard/google/snow/mainboard.c | 943 ++++++++++++++++ src/mainboard/google/snow/romstage.c | 289 +++++ src/mainboard/google/snow/smdk5250_spl.c | 123 ++ 173 files changed, 23638 insertions(+), 32 deletions(-)
diff --git a/Makefile b/Makefile index 6e8bd0d..3c537a5 100644 --- a/Makefile +++ b/Makefile @@ -113,14 +113,14 @@ else
include $(HAVE_DOTCONFIG)
-ARCHDIR-$(CONFIG_ARCH_ARMV7) := armv7 +ARCHDIR-$(CONFIG_ARCH_ARMV7) := armv7 ARCHDIR-$(CONFIG_ARCH_X86) := x86
ARCH-y := $(ARCHDIR-y)
# If architecture folder name is different from GCC binutils architecture name, # override here. -ARCH-$(CONFIG_ARCH_ARMV7) := armv7 +ARCH-$(CONFIG_ARCH_ARMV7) := armv7 ARCH-$(CONFIG_ARCH_X86) := i386
CC := $(CC_$(ARCH-y)) diff --git a/config.snow b/config.snow new file mode 100644 index 0000000..2aaae18 --- /dev/null +++ b/config.snow @@ -0,0 +1,323 @@ +# +# Automatically generated make config: don't edit +# coreboot version: 4.0-3132-g0af95ea +# Tue Dec 4 14:41:24 2012 +# + +# +# General setup +# +# CONFIG_EXPERT is not set +CONFIG_LOCALVERSION="" +CONFIG_CBFS_PREFIX="fallback" +CONFIG_COMPILER_GCC=y +# CONFIG_COMPILER_LLVM_CLANG is not set +# CONFIG_SCANBUILD_ENABLE is not set +# CONFIG_CCACHE is not set +# CONFIG_USE_OPTION_TABLE is not set +CONFIG_COMPRESS_RAMSTAGE=y +CONFIG_INCLUDE_CONFIG_FILE=y +# CONFIG_EARLY_CBMEM_INIT is not set +# CONFIG_USE_BLOBS is not set +# CONFIG_REQUIRES_BLOB is not set + +# +# Mainboard +# +# CONFIG_VENDOR_AAEON is not set +# CONFIG_VENDOR_ABIT is not set +# CONFIG_VENDOR_ADVANSUS is not set +# CONFIG_VENDOR_ADVANTECH is not set +# CONFIG_VENDOR_AMD is not set +# CONFIG_VENDOR_AOPEN is not set +# CONFIG_VENDOR_ARIMA is not set +# CONFIG_VENDOR_ARTECGROUP is not set +# CONFIG_VENDOR_ASI is not set +# CONFIG_VENDOR_ASROCK is not set +# CONFIG_VENDOR_ASUS is not set +# CONFIG_VENDOR_A_TREND is not set +# CONFIG_VENDOR_AVALUE is not set +# CONFIG_VENDOR_AXUS is not set +# CONFIG_VENDOR_AZZA is not set +# CONFIG_VENDOR_BACHMANN is not set +# CONFIG_VENDOR_BCOM is not set +# CONFIG_VENDOR_BIFFEROS is not set +# CONFIG_VENDOR_BIOSTAR is not set +# CONFIG_VENDOR_BROADCOM is not set +# CONFIG_VENDOR_COMPAQ is not set +# CONFIG_VENDOR_DIGITALLOGIC is not set +# CONFIG_VENDOR_EAGLELION is not set +# CONFIG_VENDOR_ECS is not set +# CONFIG_VENDOR_EMULATION is not set +# CONFIG_VENDOR_GETAC is not set +# CONFIG_VENDOR_GIGABYTE is not set +CONFIG_VENDOR_GOOGLE=y +# CONFIG_VENDOR_HP is not set +# CONFIG_VENDOR_IBASE is not set +# CONFIG_VENDOR_IBM is not set +# CONFIG_VENDOR_IEI is not set +# CONFIG_VENDOR_INTEL is not set +# CONFIG_VENDOR_IWAVE is not set +# CONFIG_VENDOR_IWILL is not set +# CONFIG_VENDOR_JETWAY is not set +# CONFIG_VENDOR_KONTRON is not set +# CONFIG_VENDOR_LANNER is not set +# CONFIG_VENDOR_LENOVO is not set +# CONFIG_VENDOR_LIPPERT is not set +# CONFIG_VENDOR_MITAC is not set +# CONFIG_VENDOR_MSI is not set +# CONFIG_VENDOR_NEC is not set +# CONFIG_VENDOR_NEWISYS is not set +# CONFIG_VENDOR_NOKIA is not set +# CONFIG_VENDOR_NVIDIA is not set +# CONFIG_VENDOR_PCENGINES is not set +# CONFIG_VENDOR_RCA is not set +# CONFIG_VENDOR_RODA is not set +# CONFIG_VENDOR_SAMSUNG is not set +# CONFIG_VENDOR_SIEMENS is not set +# CONFIG_VENDOR_SOYO is not set +# CONFIG_VENDOR_SUNW is not set +# CONFIG_VENDOR_SUPERMICRO is not set +# CONFIG_VENDOR_TECHNEXION is not set +# CONFIG_VENDOR_TECHNOLOGIC is not set +# CONFIG_VENDOR_TELEVIDEO is not set +# CONFIG_VENDOR_THOMSON is not set +# CONFIG_VENDOR_TRAVERSE is not set +# CONFIG_VENDOR_TYAN is not set +# CONFIG_VENDOR_VIA is not set +# CONFIG_VENDOR_WINENT is not set +# CONFIG_VENDOR_WYSE is not set +CONFIG_BOARD_SPECIFIC_OPTIONS=y +CONFIG_MAINBOARD_DIR="google/snow" +CONFIG_MAINBOARD_PART_NUMBER="SNOW" +CONFIG_MAINBOARD_VENDOR="Samsung" +CONFIG_MAX_CPUS=2 +CONFIG_RAMTOP=0x40100000 +CONFIG_HEAP_SIZE=0x4000 +CONFIG_RAMBASE=0x40000000 +CONFIG_WARNINGS_ARE_ERRORS=y +# CONFIG_ONBOARD_VGA_IS_PRIMARY is not set +# CONFIG_VGA_BIOS is not set +# CONFIG_CONSOLE_POST is not set +# CONFIG_PCI_ROM_RUN is not set +CONFIG_ACPI_SSDTX_NUM=0 +CONFIG_BOARD_GOOGLE_SNOW=y +CONFIG_SPL_TEXT_BASE=0x02023400 +CONFIG_SPL_MAX_SIZE=0x3800 +CONFIG_DRAM_SIZE_MB=2048 +CONFIG_NR_DRAM_BANKS=1 +# CONFIG_CONSOLE_SERIAL_UART0 is not set +# CONFIG_CONSOLE_SERIAL_UART1 is not set +# CONFIG_CONSOLE_SERIAL_UART2 is not set +CONFIG_CONSOLE_SERIAL_UART3=y +CONFIG_CONSOLE_SERIAL_UART_ADDRESS=0x12c30000 +CONFIG_SYS_I2C_SPEED=100000 +CONFIG_SYS_I2C_SLAVE=0x0 +CONFIG_I2C_MULTI_BUS=y +CONFIG_VDD_ARM_MV=1300 +CONFIG_VDD_INT_UV=1012500 +CONFIG_VDD_MIF_MV=1000 +CONFIG_VDD_G3D_MV=1200 +CONFIG_VDD_LDO2_MV=1500 +CONFIG_VDD_LDO3_MV=1800 +CONFIG_VDD_LDO5_MV=1800 +CONFIG_VDD_LDO10_MV=1800 +# CONFIG_MMCONF_SUPPORT_DEFAULT is not set +# CONFIG_POWER_BUTTON_FORCE_ENABLE is not set +# CONFIG_IOAPIC is not set +CONFIG_TTYS0_BAUD=115200 +CONFIG_DEFAULT_CONSOLE_LOGLEVEL=8 +CONFIG_MAXIMUM_CONSOLE_LOGLEVEL=8 +# CONFIG_CONSOLE_SERIAL8250 is not set +# CONFIG_USBDEBUG is not set +CONFIG_BOARD_ROMSIZE_KB_4096=y +# CONFIG_COREBOOT_ROMSIZE_KB_64 is not set +# CONFIG_COREBOOT_ROMSIZE_KB_128 is not set +# CONFIG_COREBOOT_ROMSIZE_KB_256 is not set +# CONFIG_COREBOOT_ROMSIZE_KB_512 is not set +# CONFIG_COREBOOT_ROMSIZE_KB_1024 is not set +# CONFIG_COREBOOT_ROMSIZE_KB_2048 is not set +CONFIG_COREBOOT_ROMSIZE_KB_4096=y +# CONFIG_COREBOOT_ROMSIZE_KB_8192 is not set +# CONFIG_COREBOOT_ROMSIZE_KB_16384 is not set +CONFIG_COREBOOT_ROMSIZE_KB=4096 +CONFIG_ROM_SIZE=0x400000 +CONFIG_CACHE_ROM_SIZE=0x400000 +# CONFIG_ARCH_X86 is not set +# CONFIG_ARCH_ARM is not set +CONFIG_ARCH_ARMV7=y +CONFIG_MAX_REBOOT_CNT=3 +CONFIG_BOOTBLOCK_SOURCE="bootblock_simple.c" + +# +# Architecture (armv7) +# +CONFIG_SPL_BUILD=y +# CONFIG_EABI_COMPAT is not set +CONFIG_ARM_BOOTBLOCK_SIMPLE=y +# CONFIG_ARM_BOOTBLOCK_NORMAL is not set +CONFIG_ARM_DCACHE_POLICY_WRITEBACK=y +# CONFIG_ARM_DCACHE_POLICY_WRITETHROUGH is not set + +# +# Chipset +# + +# +# CPU +# +CONFIG_CPU_SAMSUNG_EXYNOS=y +CONFIG_CPU_SAMSUNG_EXYNOS5=y +# CONFIG_SKIP_LOWLEVEL_INIT is not set +CONFIG_IRAM_BOTTOM=0x02020000 +CONFIG_IRAM_TOP=0x02077fff +CONFIG_SYS_INIT_SP_ADDR=0x0204F800 +CONFIG_IRAM_STACK=0x0204F800 +CONFIG_XIP_ROM_SIZE=0x20000 +# CONFIG_EXYNOS_ACE_SHA is not set +# CONFIG_SATA_AHCI is not set +CONFIG_SYS_TEXT_BASE=0x43e00000 +CONFIG_SYS_SDRAM_BASE=0x40000000 +CONFIG_HAVE_INIT_TIMER=y +CONFIG_HIGH_SCRATCH_MEMORY_SIZE=0x0 +# CONFIG_CPU_MICROCODE_IN_CBFS is not set +# CONFIG_CPU_MICROCODE_CBFS_GENERATE is not set +# CONFIG_CPU_MICROCODE_CBFS_EXTERNAL is not set +CONFIG_CPU_MICROCODE_CBFS_NONE=y + +# +# Northbridge +# +CONFIG_VIDEO_MB=0 +# CONFIG_NORTHBRIDGE_AMD_AGESA is not set +# CONFIG_AMD_NB_CIMX is not set +# CONFIG_NORTHBRIDGE_AMD_CIMX_RD890 is not set +CONFIG_CBFS_SIZE=0x400000 + +# +# Southbridge +# +# CONFIG_AMD_SB_CIMX is not set +# CONFIG_SOUTHBRIDGE_AMD_CIMX_SB800 is not set +# CONFIG_SOUTHBRIDGE_AMD_CIMX_SB900 is not set +# CONFIG_SPI_FLASH is not set + +# +# Super I/O +# + +# +# Embedded Controllers +# + +# +# Devices +# +# CONFIG_VGA_ROM_RUN is not set +# CONFIG_ON_DEVICE_ROM_RUN is not set +# CONFIG_MULTIPLE_VGA_ADAPTERS is not set +# CONFIG_PCI is not set +# CONFIG_PCIEXP_COMMON_CLOCK is not set +# CONFIG_PCIEXP_ASPM is not set +CONFIG_PCI_BUS_SEGN_BITS=0 + +# +# VGA BIOS +# + +# +# Generic Drivers +# +# CONFIG_IPMI_KCS is not set +# CONFIG_DRIVERS_OXFORD_OXPCIE is not set +# CONFIG_RTL8168_ROM_DISABLE is not set +# CONFIG_DRIVERS_SIL_3114 is not set +CONFIG_DRIVER_MAXIM_77686=y +# CONFIG_MMCONF_SUPPORT is not set + +# +# Console +# +CONFIG_SERIAL_CONSOLE=y +# CONFIG_CONSOLE_SERIAL8250MEM is not set +CONFIG_CONSOLE_SERIAL_NONSTANDARD_MEM=y +CONFIG_CONSOLE_SERIAL_115200=y +# CONFIG_CONSOLE_SERIAL_57600 is not set +# CONFIG_CONSOLE_SERIAL_38400 is not set +# CONFIG_CONSOLE_SERIAL_19200 is not set +# CONFIG_CONSOLE_SERIAL_9600 is not set +# CONFIG_HAVE_USBDEBUG is not set +# CONFIG_CONSOLE_NE2K is not set +CONFIG_MAXIMUM_CONSOLE_LOGLEVEL_8=y +# CONFIG_MAXIMUM_CONSOLE_LOGLEVEL_7 is not set +# CONFIG_MAXIMUM_CONSOLE_LOGLEVEL_6 is not set +# CONFIG_MAXIMUM_CONSOLE_LOGLEVEL_5 is not set +# CONFIG_MAXIMUM_CONSOLE_LOGLEVEL_4 is not set +# CONFIG_MAXIMUM_CONSOLE_LOGLEVEL_3 is not set +# CONFIG_MAXIMUM_CONSOLE_LOGLEVEL_2 is not set +# CONFIG_MAXIMUM_CONSOLE_LOGLEVEL_1 is not set +# CONFIG_MAXIMUM_CONSOLE_LOGLEVEL_0 is not set +CONFIG_DEFAULT_CONSOLE_LOGLEVEL_8=y +# CONFIG_DEFAULT_CONSOLE_LOGLEVEL_7 is not set +# CONFIG_DEFAULT_CONSOLE_LOGLEVEL_6 is not set +# CONFIG_DEFAULT_CONSOLE_LOGLEVEL_5 is not set +# CONFIG_DEFAULT_CONSOLE_LOGLEVEL_4 is not set +# CONFIG_DEFAULT_CONSOLE_LOGLEVEL_3 is not set +# CONFIG_DEFAULT_CONSOLE_LOGLEVEL_2 is not set +# CONFIG_DEFAULT_CONSOLE_LOGLEVEL_1 is not set +# CONFIG_DEFAULT_CONSOLE_LOGLEVEL_0 is not set +# CONFIG_CONSOLE_LOGBUF is not set +# CONFIG_NO_POST is not set +# CONFIG_CMOS_POST is not set +# CONFIG_IO_POST is not set +CONFIG_HAVE_UART_IO_MAPPED=y +CONFIG_HAVE_UART_MEMORY_MAPPED=y +# CONFIG_HAVE_ACPI_RESUME is not set +# CONFIG_HAVE_ACPI_SLIC is not set +# CONFIG_HAVE_HARD_RESET is not set +# CONFIG_HAVE_OPTION_TABLE is not set +# CONFIG_PIRQ_ROUTE is not set +# CONFIG_HAVE_SMI_HANDLER is not set +# CONFIG_PCI_IO_CFG_EXT is not set +# CONFIG_USE_WATCHDOG_ON_BOOT is not set +# CONFIG_VGA is not set +# CONFIG_GFXUMA is not set +CONFIG_MAX_PIRQ_LINKS=4 + +# +# System tables +# +CONFIG_WRITE_HIGH_TABLES=y +CONFIG_MULTIBOOT=y +# CONFIG_GENERATE_ACPI_TABLES is not set +# CONFIG_GENERATE_MP_TABLE is not set +# CONFIG_GENERATE_PIRQ_TABLE is not set + +# +# Payload +# +CONFIG_PAYLOAD_NONE=y +# CONFIG_PAYLOAD_ELF is not set +# CONFIG_PAYLOAD_SEABIOS is not set +# CONFIG_PAYLOAD_FILO is not set +# CONFIG_COMPRESSED_PAYLOAD_NRV2B is not set + +# +# Debugging +# +# CONFIG_GDB_STUB is not set +# CONFIG_HAVE_DEBUG_RAM_SETUP is not set +# CONFIG_HAVE_DEBUG_CAR is not set +# CONFIG_HAVE_DEBUG_SMBUS is not set +# CONFIG_DEBUG_MALLOC is not set +# CONFIG_DEBUG_ACPI is not set +# CONFIG_LLSHELL is not set +# CONFIG_TRACE is not set +# CONFIG_AP_CODE_IN_CAR is not set +# CONFIG_RAMINIT_SYSINFO is not set +# CONFIG_ENABLE_APIC_EXT_ID is not set +# CONFIG_POWER_BUTTON_DEFAULT_ENABLE is not set +# CONFIG_POWER_BUTTON_DEFAULT_DISABLE is not set +# CONFIG_POWER_BUTTON_FORCE_DISABLE is not set +# CONFIG_POWER_BUTTON_IS_OPTIONAL is not set +# CONFIG_CHROMEOS is not set diff --git a/src/arch/armv7/Kconfig b/src/arch/armv7/Kconfig index 00e6549..f92911d 100644 --- a/src/arch/armv7/Kconfig +++ b/src/arch/armv7/Kconfig @@ -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 diff --git a/src/arch/armv7/Makefile.inc b/src/arch/armv7/Makefile.inc new file mode 100644 index 0000000..076a93f --- /dev/null +++ b/src/arch/armv7/Makefile.inc @@ -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 $@ + diff --git a/src/arch/armv7/boot/Makefile.inc b/src/arch/armv7/boot/Makefile.inc new file mode 100644 index 0000000..a0752d6 --- /dev/null +++ b/src/arch/armv7/boot/Makefile.inc @@ -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 diff --git a/src/arch/armv7/boot/acpi.c b/src/arch/armv7/boot/acpi.c new file mode 100644 index 0000000..4d405d9 --- /dev/null +++ b/src/arch/armv7/boot/acpi.c @@ -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; +} diff --git a/src/arch/armv7/boot/acpigen.c b/src/arch/armv7/boot/acpigen.c new file mode 100644 index 0000000..47845a0 --- /dev/null +++ b/src/arch/armv7/boot/acpigen.c @@ -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; +} diff --git a/src/arch/armv7/boot/boot.c b/src/arch/armv7/boot/boot.c new file mode 100644 index 0000000..722fca5 --- /dev/null +++ b/src/arch/armv7/boot/boot.c @@ -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 +} + + diff --git a/src/arch/armv7/boot/coreboot_table.c b/src/arch/armv7/boot/coreboot_table.c new file mode 100644 index 0000000..9f67da0 --- /dev/null +++ b/src/arch/armv7/boot/coreboot_table.c @@ -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); + +} diff --git a/src/arch/armv7/boot/multiboot.c b/src/arch/armv7/boot/multiboot.c new file mode 100644 index 0000000..4059f27 --- /dev/null +++ b/src/arch/armv7/boot/multiboot.c @@ -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; +} diff --git a/src/arch/armv7/boot/tables.c b/src/arch/armv7/boot/tables.c new file mode 100644 index 0000000..07c5635 --- /dev/null +++ b/src/arch/armv7/boot/tables.c @@ -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(); +} diff --git a/src/arch/armv7/boot/wakeup.S b/src/arch/armv7/boot/wakeup.S new file mode 100644 index 0000000..8ae337c --- /dev/null +++ b/src/arch/armv7/boot/wakeup.S @@ -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) + diff --git a/src/arch/armv7/bootblock_simple.c b/src/arch/armv7/bootblock_simple.c new file mode 100644 index 0000000..f447a29 --- /dev/null +++ b/src/arch/armv7/bootblock_simple.c @@ -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(); +} + diff --git a/src/arch/armv7/coreboot_ram.ld b/src/arch/armv7/coreboot_ram.ld new file mode 100644 index 0000000..57ddd03 --- /dev/null +++ b/src/arch/armv7/coreboot_ram.ld @@ -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.*) + } +} diff --git a/src/arch/armv7/cpu.c b/src/arch/armv7/cpu.c new file mode 100644 index 0000000..622e7ed --- /dev/null +++ b/src/arch/armv7/cpu.c @@ -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 diff --git a/src/arch/armv7/include/arch/atomic.h b/src/arch/armv7/include/arch/atomic.h new file mode 100644 index 0000000..5a8954f --- /dev/null +++ b/src/arch/armv7/include/arch/atomic.h @@ -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 diff --git a/src/arch/armv7/include/arch/boot/boot.h b/src/arch/armv7/include/arch/boot/boot.h new file mode 100644 index 0000000..08651cd --- /dev/null +++ b/src/arch/armv7/include/arch/boot/boot.h @@ -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 */ diff --git a/src/arch/armv7/include/arch/byteorder.h b/src/arch/armv7/include/arch/byteorder.h new file mode 100644 index 0000000..8dc069f --- /dev/null +++ b/src/arch/armv7/include/arch/byteorder.h @@ -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 */ diff --git a/src/arch/armv7/include/arch/coreboot_tables.h b/src/arch/armv7/include/arch/coreboot_tables.h new file mode 100644 index 0000000..3c9bf98 --- /dev/null +++ b/src/arch/armv7/include/arch/coreboot_tables.h @@ -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 */ diff --git a/src/arch/armv7/include/arch/cpu.h b/src/arch/armv7/include/arch/cpu.h index b68004a..20a12c9 100644 --- a/src/arch/armv7/include/arch/cpu.h +++ b/src/arch/armv7/include/arch/cpu.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__ */ diff --git a/src/arch/armv7/include/arch/gpio.h b/src/arch/armv7/include/arch/gpio.h new file mode 100644 index 0000000..b5dd9b7 --- /dev/null +++ b/src/arch/armv7/include/arch/gpio.h @@ -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_ */ diff --git a/src/arch/armv7/include/arch/hlt.h b/src/arch/armv7/include/arch/hlt.h new file mode 100644 index 0000000..535508a --- /dev/null +++ b/src/arch/armv7/include/arch/hlt.h @@ -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 */ diff --git a/src/arch/armv7/include/arch/io.h b/src/arch/armv7/include/arch/io.h new file mode 100644 index 0000000..7e64472 --- /dev/null +++ b/src/arch/armv7/include/arch/io.h @@ -0,0 +1,473 @@ +/* + * 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> +#include <asm/memory.h> +#if 0 /* XXX###XXX */ +#include <asm/arch/hardware.h> +#endif /* XXX###XXX */ + +static inline void sync(void) +{ +} + +/* + * Given a physical address and a length, return a virtual address + * that can be used to access the memory range with the caching + * properties specified by "flags". + */ +#define MAP_NOCACHE (0) +#define MAP_WRCOMBINE (0) +#define MAP_WRBACK (0) +#define MAP_WRTHROUGH (0) + +static inline void * +map_physmem(phys_addr_t paddr, unsigned long len, unsigned long flags) +{ + return (void *)paddr; +} + +/* + * Take down a mapping set up by map_physmem(). + */ +static inline void unmap_physmem(void *vaddr, unsigned long flags) +{ + +} + +#if 0 +static inline phys_addr_t virt_to_phys(void * vaddr) +{ + return (phys_addr_t)(vaddr); +} +#endif + +/* + * 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 + +#define ioremap(off,sz) __arch_ioremap((off),(sz),0) +#define ioremap_nocache(off,sz) __arch_ioremap((off),(sz),1) +#define iounmap(_addr) __arch_iounmap(_addr) + +/* + * DMA-consistent mapping functions. These allocate/free a region of + * uncached, unwrite-buffered mapped memory space for use with DMA + * devices. This is the "generic" version. The PCI specific version + * is in pci.h + */ +extern void *consistent_alloc(int gfp, size_t size, dma_addr_t *handle); +extern void consistent_free(void *vaddr, size_t size, dma_addr_t handle); +extern void consistent_sync(void *vaddr, size_t size, int rw); + +/* + * 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 */ diff --git a/src/arch/armv7/include/arch/pci_ops.h b/src/arch/armv7/include/arch/pci_ops.h new file mode 100644 index 0000000..eca9390 --- /dev/null +++ b/src/arch/armv7/include/arch/pci_ops.h @@ -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 */ diff --git a/src/arch/armv7/include/arch/types.h b/src/arch/armv7/include/arch/types.h new file mode 100644 index 0000000..71dc049 --- /dev/null +++ b/src/arch/armv7/include/arch/types.h @@ -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 diff --git a/src/arch/armv7/include/armv7.h b/src/arch/armv7/include/armv7.h new file mode 100644 index 0000000..dc111c1 --- /dev/null +++ b/src/arch/armv7/include/armv7.h @@ -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 diff --git a/src/arch/armv7/include/asm/bitops.h b/src/arch/armv7/include/asm/bitops.h new file mode 100644 index 0000000..1c961dd --- /dev/null +++ b/src/arch/armv7/include/asm/bitops.h @@ -0,0 +1,316 @@ +/* + * Copyright 1995, Russell King. + * Various bits and pieces copyrights include: + * Linus Torvalds (test_bit). + * Big endian support: Copyright 2001, Nicolas Pitre + * reworked by rmk. + * + * bit 0 is the LSB of an "unsigned long" quantity. + * + * Please note that the code in this file should never be included + * from user space. Many of these are not implemented in assembler + * since they would be too costly. Also, they require privileged + * instructions (which are not available from user mode) to ensure + * that they are atomic. + */ + +#ifndef __ASM_ARM_BITOPS_H +#define __ASM_ARM_BITOPS_H + +#ifdef __KERNEL__ + +#ifndef _LINUX_BITOPS_H +#error only <linux/bitops.h> can be included directly +#endif + +#include <linux/irqflags.h> + +#define smp_mb__before_clear_bit() smp_mb() +#define smp_mb__after_clear_bit() smp_mb() + +/* + * These functions are the basis of our bit ops. + * + * First, the atomic bitops. These use native endian. + */ +static inline void ____atomic_set_bit(unsigned int bit, volatile unsigned long *p) +{ + unsigned long flags; + unsigned long mask = 1UL << (bit & 31); + + p += bit >> 5; + + raw_local_irq_save(flags); + *p |= mask; + raw_local_irq_restore(flags); +} + +static inline void ____atomic_clear_bit(unsigned int bit, volatile unsigned long *p) +{ + unsigned long flags; + unsigned long mask = 1UL << (bit & 31); + + p += bit >> 5; + + raw_local_irq_save(flags); + *p &= ~mask; + raw_local_irq_restore(flags); +} + +static inline void ____atomic_change_bit(unsigned int bit, volatile unsigned long *p) +{ + unsigned long flags; + unsigned long mask = 1UL << (bit & 31); + + p += bit >> 5; + + raw_local_irq_save(flags); + *p ^= mask; + raw_local_irq_restore(flags); +} + +static inline int +____atomic_test_and_set_bit(unsigned int bit, volatile unsigned long *p) +{ + unsigned long flags; + unsigned int res; + unsigned long mask = 1UL << (bit & 31); + + p += bit >> 5; + + raw_local_irq_save(flags); + res = *p; + *p = res | mask; + raw_local_irq_restore(flags); + + return (res & mask) != 0; +} + +static inline int +____atomic_test_and_clear_bit(unsigned int bit, volatile unsigned long *p) +{ + unsigned long flags; + unsigned int res; + unsigned long mask = 1UL << (bit & 31); + + p += bit >> 5; + + raw_local_irq_save(flags); + res = *p; + *p = res & ~mask; + raw_local_irq_restore(flags); + + return (res & mask) != 0; +} + +static inline int +____atomic_test_and_change_bit(unsigned int bit, volatile unsigned long *p) +{ + unsigned long flags; + unsigned int res; + unsigned long mask = 1UL << (bit & 31); + + p += bit >> 5; + + raw_local_irq_save(flags); + res = *p; + *p = res ^ mask; + raw_local_irq_restore(flags); + + return (res & mask) != 0; +} + +#include <asm-generic/bitops/non-atomic.h> + +/* + * A note about Endian-ness. + * ------------------------- + * + * When the ARM is put into big endian mode via CR15, the processor + * merely swaps the order of bytes within words, thus: + * + * ------------ physical data bus bits ----------- + * D31 ... D24 D23 ... D16 D15 ... D8 D7 ... D0 + * little byte 3 byte 2 byte 1 byte 0 + * big byte 0 byte 1 byte 2 byte 3 + * + * This means that reading a 32-bit word at address 0 returns the same + * value irrespective of the endian mode bit. + * + * Peripheral devices should be connected with the data bus reversed in + * "Big Endian" mode. ARM Application Note 61 is applicable, and is + * available from http://www.arm.com/. + * + * The following assumes that the data bus connectivity for big endian + * mode has been followed. + * + * Note that bit 0 is defined to be 32-bit word bit 0, not byte 0 bit 0. + */ + +/* + * Native endian assembly bitops. nr = 0 -> word 0 bit 0. + */ +extern void _set_bit(int nr, volatile unsigned long * p); +extern void _clear_bit(int nr, volatile unsigned long * p); +extern void _change_bit(int nr, volatile unsigned long * p); +extern int _test_and_set_bit(int nr, volatile unsigned long * p); +extern int _test_and_clear_bit(int nr, volatile unsigned long * p); +extern int _test_and_change_bit(int nr, volatile unsigned long * p); + +/* + * Little endian assembly bitops. nr = 0 -> byte 0 bit 0. + */ +extern int _find_first_zero_bit_le(const void * p, unsigned size); +extern int _find_next_zero_bit_le(const void * p, int size, int offset); +extern int _find_first_bit_le(const unsigned long *p, unsigned size); +extern int _find_next_bit_le(const unsigned long *p, int size, int offset); + +/* + * Big endian assembly bitops. nr = 0 -> byte 3 bit 0. + */ +extern int _find_first_zero_bit_be(const void * p, unsigned size); +extern int _find_next_zero_bit_be(const void * p, int size, int offset); +extern int _find_first_bit_be(const unsigned long *p, unsigned size); +extern int _find_next_bit_be(const unsigned long *p, int size, int offset); + +#ifndef CONFIG_SMP +/* + * The __* form of bitops are non-atomic and may be reordered. + */ +#define ATOMIC_BITOP(name,nr,p) \ + (__builtin_constant_p(nr) ? ____atomic_##name(nr, p) : _##name(nr,p)) +#else +#define ATOMIC_BITOP(name,nr,p) _##name(nr,p) +#endif + +/* + * Native endian atomic definitions. + */ +#define set_bit(nr,p) ATOMIC_BITOP(set_bit,nr,p) +#define clear_bit(nr,p) ATOMIC_BITOP(clear_bit,nr,p) +#define change_bit(nr,p) ATOMIC_BITOP(change_bit,nr,p) +#define test_and_set_bit(nr,p) ATOMIC_BITOP(test_and_set_bit,nr,p) +#define test_and_clear_bit(nr,p) ATOMIC_BITOP(test_and_clear_bit,nr,p) +#define test_and_change_bit(nr,p) ATOMIC_BITOP(test_and_change_bit,nr,p) + +#ifndef __ARMEB__ +/* + * These are the little endian, atomic definitions. + */ +#define find_first_zero_bit(p,sz) _find_first_zero_bit_le(p,sz) +#define find_next_zero_bit(p,sz,off) _find_next_zero_bit_le(p,sz,off) +#define find_first_bit(p,sz) _find_first_bit_le(p,sz) +#define find_next_bit(p,sz,off) _find_next_bit_le(p,sz,off) + +#else +/* + * These are the big endian, atomic definitions. + */ +#define find_first_zero_bit(p,sz) _find_first_zero_bit_be(p,sz) +#define find_next_zero_bit(p,sz,off) _find_next_zero_bit_be(p,sz,off) +#define find_first_bit(p,sz) _find_first_bit_be(p,sz) +#define find_next_bit(p,sz,off) _find_next_bit_be(p,sz,off) + +#endif + +#if __LINUX_ARM_ARCH__ < 5 + +#include <asm-generic/bitops/ffz.h> +#include <asm-generic/bitops/__fls.h> +#include <asm-generic/bitops/__ffs.h> +#include <asm-generic/bitops/fls.h> +#include <asm-generic/bitops/ffs.h> + +#else + +static inline int constant_fls(int x) +{ + int r = 32; + + if (!x) + return 0; + if (!(x & 0xffff0000u)) { + x <<= 16; + r -= 16; + } + if (!(x & 0xff000000u)) { + x <<= 8; + r -= 8; + } + if (!(x & 0xf0000000u)) { + x <<= 4; + r -= 4; + } + if (!(x & 0xc0000000u)) { + x <<= 2; + r -= 2; + } + if (!(x & 0x80000000u)) { + x <<= 1; + r -= 1; + } + return r; +} + +/* + * On ARMv5 and above those functions can be implemented around + * the clz instruction for much better code efficiency. + */ + +static inline int fls(int x) +{ + int ret; + + if (__builtin_constant_p(x)) + return constant_fls(x); + + asm("clz\t%0, %1" : "=r" (ret) : "r" (x)); + ret = 32 - ret; + return ret; +} + +#define __fls(x) (fls(x) - 1) +#define ffs(x) ({ unsigned long __t = (x); fls(__t & -__t); }) +#define __ffs(x) (ffs(x) - 1) +#define ffz(x) __ffs( ~(x) ) + +#endif + +#include <asm-generic/bitops/fls64.h> + +#include <asm-generic/bitops/sched.h> +#include <asm-generic/bitops/hweight.h> +#include <asm-generic/bitops/lock.h> + +#ifdef __ARMEB__ + +static inline int find_first_zero_bit_le(const void *p, unsigned size) +{ + return _find_first_zero_bit_le(p, size); +} +#define find_first_zero_bit_le find_first_zero_bit_le + +static inline int find_next_zero_bit_le(const void *p, int size, int offset) +{ + return _find_next_zero_bit_le(p, size, offset); +} +#define find_next_zero_bit_le find_next_zero_bit_le + +static inline int find_next_bit_le(const void *p, int size, int offset) +{ + return _find_next_bit_le(p, size, offset); +} +#define find_next_bit_le find_next_bit_le + +#endif + +#include <asm-generic/bitops/le.h> + +/* + * Ext2 is defined to use little-endian byte ordering. + */ +#include <asm-generic/bitops/ext2-atomic-setbit.h> + +#endif /* __KERNEL__ */ + +#endif /* _ARM_BITOPS_H */ diff --git a/src/arch/armv7/include/asm/bitsperlong.h b/src/arch/armv7/include/asm/bitsperlong.h new file mode 100644 index 0000000..ef2bbb2 --- /dev/null +++ b/src/arch/armv7/include/asm/bitsperlong.h @@ -0,0 +1,28 @@ +/* + * This file is part of the coreboot project. + * + * Copyright (C) 2011 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 + * + * bitsperlong.h: There is no ARM-specific version of bitsperlong.h in Linux, + * so this just points to the generic bitsperlong.h. + */ + +#ifndef __ASM_ARM_BITSPERLONG_H +#define __ASM_ARM_BITSPERLONG_H + +#include <asm-generic/bitsperlong.h> + +#endif /* __ASM_ARM_BITSPERLONG_H */ diff --git a/src/arch/armv7/include/asm/irqflags.h b/src/arch/armv7/include/asm/irqflags.h new file mode 100644 index 0000000..1e6cca5 --- /dev/null +++ b/src/arch/armv7/include/asm/irqflags.h @@ -0,0 +1,155 @@ +#ifndef __ASM_ARM_IRQFLAGS_H +#define __ASM_ARM_IRQFLAGS_H + +#ifdef __KERNEL__ + +#include <asm/ptrace.h> + +/* + * CPU interrupt mask handling. + */ +#if __LINUX_ARM_ARCH__ >= 6 + +static inline unsigned long arch_local_irq_save(void) +{ + unsigned long flags; + + asm volatile( + " mrs %0, cpsr @ arch_local_irq_save\n" + " cpsid i" + : "=r" (flags) : : "memory", "cc"); + return flags; +} + +static inline void arch_local_irq_enable(void) +{ + asm volatile( + " cpsie i @ arch_local_irq_enable" + : + : + : "memory", "cc"); +} + +static inline void arch_local_irq_disable(void) +{ + asm volatile( + " cpsid i @ arch_local_irq_disable" + : + : + : "memory", "cc"); +} + +#define local_fiq_enable() __asm__("cpsie f @ __stf" : : : "memory", "cc") +#define local_fiq_disable() __asm__("cpsid f @ __clf" : : : "memory", "cc") +#else + +/* + * Save the current interrupt enable state & disable IRQs + */ +static inline unsigned long arch_local_irq_save(void) +{ + unsigned long flags, temp; + + asm volatile( + " mrs %0, cpsr @ arch_local_irq_save\n" + " orr %1, %0, #128\n" + " msr cpsr_c, %1" + : "=r" (flags), "=r" (temp) + : + : "memory", "cc"); + return flags; +} + +/* + * Enable IRQs + */ +static inline void arch_local_irq_enable(void) +{ + unsigned long temp; + asm volatile( + " mrs %0, cpsr @ arch_local_irq_enable\n" + " bic %0, %0, #128\n" + " msr cpsr_c, %0" + : "=r" (temp) + : + : "memory", "cc"); +} + +/* + * Disable IRQs + */ +static inline void arch_local_irq_disable(void) +{ + unsigned long temp; + asm volatile( + " mrs %0, cpsr @ arch_local_irq_disable\n" + " orr %0, %0, #128\n" + " msr cpsr_c, %0" + : "=r" (temp) + : + : "memory", "cc"); +} + +/* + * Enable FIQs + */ +#define local_fiq_enable() \ + ({ \ + unsigned long temp; \ + __asm__ __volatile__( \ + "mrs %0, cpsr @ stf\n" \ +" bic %0, %0, #64\n" \ +" msr cpsr_c, %0" \ + : "=r" (temp) \ + : \ + : "memory", "cc"); \ + }) + +/* + * Disable FIQs + */ +#define local_fiq_disable() \ + ({ \ + unsigned long temp; \ + __asm__ __volatile__( \ + "mrs %0, cpsr @ clf\n" \ +" orr %0, %0, #64\n" \ +" msr cpsr_c, %0" \ + : "=r" (temp) \ + : \ + : "memory", "cc"); \ + }) + +#endif + +/* + * Save the current interrupt enable state. + */ +static inline unsigned long arch_local_save_flags(void) +{ + unsigned long flags; + asm volatile( + " mrs %0, cpsr @ local_save_flags" + : "=r" (flags) : : "memory", "cc"); + return flags; +} + +/* + * restore saved IRQ & FIQ state + */ +static inline void arch_local_irq_restore(unsigned long flags) +{ + asm volatile( + " msr cpsr_c, %0 @ local_irq_restore" + : + : "r" (flags) + : "memory", "cc"); +} + +static inline int arch_irqs_disabled_flags(unsigned long flags) +{ + return flags & PSR_I_BIT; +} + +#endif +#endif diff --git a/src/arch/armv7/include/asm/memory.h b/src/arch/armv7/include/asm/memory.h new file mode 100644 index 0000000..c7cc9e7 --- /dev/null +++ b/src/arch/armv7/include/asm/memory.h @@ -0,0 +1,300 @@ +/* + * arch/arm/include/asm/memory.h + * + * Copyright (C) 2000-2002 Russell King + * modification for nommu, Hyok S. Choi, 2004 + * + * 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. + * + * Note: this file should not be included by non-asm/.h files + */ +#ifndef __ASM_ARM_MEMORY_H +#define __ASM_ARM_MEMORY_H + +//#include <linux/const.h> +#include <types.h> +#include <arch/types.h> +//typedef uintptr_t phys_addr_t; +//#include <linux/sizes.h> + +#ifdef CONFIG_NEED_MACH_MEMORY_H +#include <mach/memory.h> +#endif + +/* FIXME(dhendrix): U-Boot <--> Linux #defines */ +#ifdef CONFIG_SYS_SDRAM_BASE +#define CONFIG_DRAM_BASE CONFIG_SYS_SDRAM_BASE +#endif +#ifdef CONFIG_DRAM_SIZE_MB +#define CONFIG_DRAM_SIZE (CONFIG_DRAM_BASE * 1024) +#endif + +/* + * Allow for constants defined here to be used from assembly code + * by prepending the UL suffix only with actual C code compilation. + */ +#ifdef __ASSEMBLY__ +#define _AC(X,Y) X +#else +#define __AC(X,Y) (X##Y) +#define _AC(X,Y) __AC(X,Y) +#endif + +#define UL(x) _AC(x, UL) + +#ifdef CONFIG_MMU + +/* + * PAGE_OFFSET - the virtual address of the start of the kernel image + * TASK_SIZE - the maximum size of a user space task. + * TASK_UNMAPPED_BASE - the lower boundary of the mmap VM area + */ +#define PAGE_OFFSET UL(CONFIG_PAGE_OFFSET) +#define TASK_SIZE (UL(CONFIG_PAGE_OFFSET) - UL(0x01000000)) +#define TASK_UNMAPPED_BASE (UL(CONFIG_PAGE_OFFSET) / 3) + +/* + * The maximum size of a 26-bit user space task. + */ +#define TASK_SIZE_26 UL(0x04000000) + +/* + * The module space lives between the addresses given by TASK_SIZE + * and PAGE_OFFSET - it must be within 32MB of the kernel text. + */ +#ifndef CONFIG_THUMB2_KERNEL +#define MODULES_VADDR (PAGE_OFFSET - 16*1024*1024) +#else +/* smaller range for Thumb-2 symbols relocation (2^24)*/ +#define MODULES_VADDR (PAGE_OFFSET - 8*1024*1024) +#endif + +#if TASK_SIZE > MODULES_VADDR +#error Top of user space clashes with start of module space +#endif + +/* + * The highmem pkmap virtual space shares the end of the module area. + */ +#ifdef CONFIG_HIGHMEM +#define MODULES_END (PAGE_OFFSET - PMD_SIZE) +#else +#define MODULES_END (PAGE_OFFSET) +#endif + +/* + * The XIP kernel gets mapped at the bottom of the module vm area. + * Since we use sections to map it, this macro replaces the physical address + * with its virtual address while keeping offset from the base section. + */ +#define XIP_VIRT_ADDR(physaddr) (MODULES_VADDR + ((physaddr) & 0x000fffff)) + +/* + * Allow 16MB-aligned ioremap pages + */ +#define IOREMAP_MAX_ORDER 24 + +#define CONSISTENT_END (0xffe00000UL) + +#else /* CONFIG_MMU */ + +/* + * The limitation of user task size can grow up to the end of free ram region. + * It is difficult to define and perhaps will never meet the original meaning + * of this define that was meant to. + * Fortunately, there is no reference for this in noMMU mode, for now. + */ +#ifndef TASK_SIZE +#define TASK_SIZE (CONFIG_DRAM_SIZE) +#endif + +#ifndef TASK_UNMAPPED_BASE +#define TASK_UNMAPPED_BASE UL(0x00000000) +#endif + +#ifndef PHYS_OFFSET +#define PHYS_OFFSET UL(CONFIG_DRAM_BASE) +#endif + +#ifndef END_MEM +#define END_MEM (UL(CONFIG_DRAM_BASE) + CONFIG_DRAM_SIZE) +#endif + +#ifndef PAGE_OFFSET +#define PAGE_OFFSET (PHYS_OFFSET) +#endif + +/* + * The module can be at any place in ram in nommu mode. + */ +#define MODULES_END (END_MEM) +#define MODULES_VADDR (PHYS_OFFSET) + +#define XIP_VIRT_ADDR(physaddr) (physaddr) + +#endif /* !CONFIG_MMU */ + +/* + * We fix the TCM memories max 32 KiB ITCM resp DTCM at these + * locations + */ +#ifdef CONFIG_HAVE_TCM +#define ITCM_OFFSET UL(0xfffe0000) +#define DTCM_OFFSET UL(0xfffe8000) +#endif + +/* + * Convert a physical address to a Page Frame Number and back + */ +#define __phys_to_pfn(paddr) ((unsigned long)((paddr) >> PAGE_SHIFT)) +#define __pfn_to_phys(pfn) ((phys_addr_t)(pfn) << PAGE_SHIFT) + +/* + * Convert a page to/from a physical address + */ +#define page_to_phys(page) (__pfn_to_phys(page_to_pfn(page))) +#define phys_to_page(phys) (pfn_to_page(__phys_to_pfn(phys))) + +#ifndef __ASSEMBLY__ + +/* + * Physical vs virtual RAM address space conversion. These are + * private definitions which should NOT be used outside memory.h + * files. Use virt_to_phys/phys_to_virt/__pa/__va instead. + */ +#ifndef __virt_to_phys +#ifdef CONFIG_ARM_PATCH_PHYS_VIRT + +/* + * Constants used to force the right instruction encodings and shifts + * so that all we need to do is modify the 8-bit constant field. + */ +#define __PV_BITS_31_24 0x81000000 + +extern unsigned long __pv_phys_offset; +#define PHYS_OFFSET __pv_phys_offset + +#define __pv_stub(from,to,instr,type) \ + __asm__("@ __pv_stub\n" \ + "1: " instr " %0, %1, %2\n" \ + " .pushsection .pv_table,"a"\n" \ + " .long 1b\n" \ + " .popsection\n" \ + : "=r" (to) \ + : "r" (from), "I" (type)) + +static inline unsigned long __virt_to_phys(unsigned long x) +{ + unsigned long t; + __pv_stub(x, t, "add", __PV_BITS_31_24); + return t; +} + +static inline unsigned long __phys_to_virt(unsigned long x) +{ + unsigned long t; + __pv_stub(x, t, "sub", __PV_BITS_31_24); + return t; +} +#else +#define __virt_to_phys(x) ((x) - PAGE_OFFSET + PHYS_OFFSET) +#define __phys_to_virt(x) ((x) - PHYS_OFFSET + PAGE_OFFSET) +#endif +#endif +#endif /* __ASSEMBLY__ */ + +#ifndef PHYS_OFFSET +#ifdef PLAT_PHYS_OFFSET +#define PHYS_OFFSET PLAT_PHYS_OFFSET +#else +#define PHYS_OFFSET UL(CONFIG_PHYS_OFFSET) +#endif +#endif + +#ifndef __ASSEMBLY__ + +/* + * PFNs are used to describe any physical page; this means + * PFN 0 == physical address 0. + * + * This is the PFN of the first RAM page in the kernel + * direct-mapped view. We assume this is the first page + * of RAM in the mem_map as well. + */ +#define PHYS_PFN_OFFSET (PHYS_OFFSET >> PAGE_SHIFT) + + +/* + * These are *only* valid on the kernel direct mapped RAM memory. + * Note: Drivers should NOT use these. They are the wrong + * translation for translating DMA addresses. Use the driver + * DMA support - see dma-mapping.h. + */ +static inline phys_addr_t virt_to_phys(const volatile void *x) +{ + return __virt_to_phys((unsigned long)(x)); +} + +static inline void *phys_to_virt(phys_addr_t x) +{ + return (void *)(__phys_to_virt((unsigned long)(x))); +} + +/* + * Drivers should NOT use these either. + */ +#define __pa(x) __virt_to_phys((unsigned long)(x)) +#define __va(x) ((void *)__phys_to_virt((unsigned long)(x))) +#define pfn_to_kaddr(pfn) __va((pfn) << PAGE_SHIFT) + +/* + * Virtual <-> DMA view memory address translations + * Again, these are *only* valid on the kernel direct mapped RAM + * memory. Use of these is *deprecated* (and that doesn't mean + * use the __ prefixed forms instead.) See dma-mapping.h. + */ +#ifndef __virt_to_bus +#define __virt_to_bus __virt_to_phys +#define __bus_to_virt __phys_to_virt +#define __pfn_to_bus(x) __pfn_to_phys(x) +#define __bus_to_pfn(x) __phys_to_pfn(x) +#endif + +#define __deprecated +static inline __deprecated unsigned long virt_to_bus(void *x) +{ + return __virt_to_bus((unsigned long)x); +} + +static inline __deprecated void *bus_to_virt(unsigned long x) +{ + return (void *)__bus_to_virt(x); +} + +/* + * Conversion between a struct page and a physical address. + * + * Note: when converting an unknown physical address to a + * struct page, the resulting pointer must be validated + * using VALID_PAGE(). It must return an invalid struct page + * for any physical address not corresponding to a system + * RAM address. + * + * page_to_pfn(page) convert a struct page * to a PFN number + * pfn_to_page(pfn) convert a _valid_ PFN number to struct page * + * + * virt_to_page(k) convert a _valid_ virtual address to struct page * + * virt_addr_valid(k) indicates whether a virtual address is valid + */ +#define ARCH_PFN_OFFSET PHYS_PFN_OFFSET + +#define virt_to_page(kaddr) pfn_to_page(__pa(kaddr) >> PAGE_SHIFT) +#define virt_addr_valid(kaddr) ((unsigned long)(kaddr) >= PAGE_OFFSET && (unsigned long)(kaddr) < (unsigned long)high_memory) + +#endif + +//#include <asm-generic/memory_model.h> + +#endif diff --git a/src/arch/armv7/include/asm/posix_types.h b/src/arch/armv7/include/asm/posix_types.h new file mode 100644 index 0000000..2446d23 --- /dev/null +++ b/src/arch/armv7/include/asm/posix_types.h @@ -0,0 +1,77 @@ +/* + * arch/arm/include/asm/posix_types.h + * + * Copyright (C) 1996-1998 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 + */ +#ifndef __ARCH_ARM_POSIX_TYPES_H +#define __ARCH_ARM_POSIX_TYPES_H + +/* + * This file is generally used by user-level software, so you need to + * be a little careful about namespace pollution etc. Also, we cannot + * assume GCC is being used. + */ + +typedef unsigned long __kernel_ino_t; +typedef unsigned short __kernel_mode_t; +typedef unsigned short __kernel_nlink_t; +typedef long __kernel_off_t; +typedef int __kernel_pid_t; +typedef unsigned short __kernel_ipc_pid_t; +typedef unsigned short __kernel_uid_t; +typedef unsigned short __kernel_gid_t; +typedef unsigned int __kernel_size_t; +typedef int __kernel_ssize_t; +typedef int __kernel_ptrdiff_t; +typedef long __kernel_time_t; +typedef long __kernel_suseconds_t; +typedef long __kernel_clock_t; +typedef int __kernel_timer_t; +typedef int __kernel_clockid_t; +typedef int __kernel_daddr_t; +typedef char * __kernel_caddr_t; +typedef unsigned short __kernel_uid16_t; +typedef unsigned short __kernel_gid16_t; +typedef unsigned int __kernel_uid32_t; +typedef unsigned int __kernel_gid32_t; + +typedef unsigned short __kernel_old_uid_t; +typedef unsigned short __kernel_old_gid_t; +typedef unsigned short __kernel_old_dev_t; + +#ifdef __GNUC__ +typedef long long __kernel_loff_t; +#endif + +typedef struct { + int val[2]; +} __kernel_fsid_t; + +#if defined(__KERNEL__) + +#undef __FD_SET +#define __FD_SET(fd, fdsetp) \ + (((fd_set *)(fdsetp))->fds_bits[(fd) >> 5] |= (1<<((fd) & 31))) + +#undef __FD_CLR +#define __FD_CLR(fd, fdsetp) \ + (((fd_set *)(fdsetp))->fds_bits[(fd) >> 5] &= ~(1<<((fd) & 31))) + +#undef __FD_ISSET +#define __FD_ISSET(fd, fdsetp) \ + ((((fd_set *)(fdsetp))->fds_bits[(fd) >> 5] & (1<<((fd) & 31))) != 0) + +#undef __FD_ZERO +#define __FD_ZERO(fdsetp) \ + (memset (fdsetp, 0, sizeof (*(fd_set *)(fdsetp)))) + +#endif + +#endif diff --git a/src/arch/armv7/include/asm/system.h b/src/arch/armv7/include/asm/system.h new file mode 100644 index 0000000..a061f8b --- /dev/null +++ b/src/arch/armv7/include/asm/system.h @@ -0,0 +1,62 @@ +#ifndef __ASM_ARM_SYSTEM_H +#define __ASM_ARM_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) + +#endif diff --git a/src/arch/armv7/include/asm/types.h b/src/arch/armv7/include/asm/types.h new file mode 100644 index 0000000..28beab9 --- /dev/null +++ b/src/arch/armv7/include/asm/types.h @@ -0,0 +1,16 @@ +#ifndef __ASM_ARM_TYPES_H +#define __ASM_ARM_TYPES_H + +#include <asm-generic/int-ll64.h> + +/* + * These aren't exported outside the kernel to avoid name space clashes + */ +#ifdef __KERNEL__ + +#define BITS_PER_LONG 32 + +#endif /* __KERNEL__ */ + +#endif + diff --git a/src/arch/armv7/include/assembler.h b/src/arch/armv7/include/assembler.h new file mode 100644 index 0000000..5e4789b --- /dev/null +++ b/src/arch/armv7/include/assembler.h @@ -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 diff --git a/src/arch/armv7/include/bootblock_common.h b/src/arch/armv7/include/bootblock_common.h new file mode 100644 index 0000000..f5c7129 --- /dev/null +++ b/src/arch/armv7/include/bootblock_common.h @@ -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"); +} diff --git a/src/arch/armv7/include/cache.h b/src/arch/armv7/include/cache.h new file mode 100644 index 0000000..7324680 --- /dev/null +++ b/src/arch/armv7/include/cache.h @@ -0,0 +1,58 @@ +/* + * (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 + +#include <asm/system.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 */ diff --git a/src/arch/armv7/include/clocks.h b/src/arch/armv7/include/clocks.h new file mode 100644 index 0000000..8f35303 --- /dev/null +++ b/src/arch/armv7/include/clocks.h @@ -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, +}; + diff --git a/src/arch/armv7/include/common.h b/src/arch/armv7/include/common.h new file mode 100644 index 0000000..e21cfb0 --- /dev/null +++ b/src/arch/armv7/include/common.h @@ -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_ */ diff --git a/src/arch/armv7/include/div64.h b/src/arch/armv7/include/div64.h new file mode 100644 index 0000000..5baed2b --- /dev/null +++ b/src/arch/armv7/include/div64.h @@ -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 diff --git a/src/arch/armv7/include/global_data.h b/src/arch/armv7/include/global_data.h new file mode 100644 index 0000000..4ae86aa --- /dev/null +++ b/src/arch/armv7/include/global_data.h @@ -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 */ diff --git a/src/arch/armv7/include/hang.h b/src/arch/armv7/include/hang.h new file mode 100644 index 0000000..f57fc28 --- /dev/null +++ b/src/arch/armv7/include/hang.h @@ -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); diff --git a/src/arch/armv7/include/mmio_conf.h b/src/arch/armv7/include/mmio_conf.h new file mode 100644 index 0000000..143c6bd --- /dev/null +++ b/src/arch/armv7/include/mmio_conf.h @@ -0,0 +1,6 @@ +#ifndef ARCH_MMIO_H +#define ARCH_MMIO_H 1 + +// Nut'n'Bitch + +#endif /* ARCH_MMIO_H */ diff --git a/src/arch/armv7/include/ptrace.h b/src/arch/armv7/include/ptrace.h new file mode 100644 index 0000000..e981cad --- /dev/null +++ b/src/arch/armv7/include/ptrace.h @@ -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 diff --git a/src/arch/armv7/include/smp/spinlock.h b/src/arch/armv7/include/smp/spinlock.h new file mode 100644 index 0000000..1dc397c --- /dev/null +++ b/src/arch/armv7/include/smp/spinlock.h @@ -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 */ diff --git a/src/arch/armv7/include/stdint.h b/src/arch/armv7/include/stdint.h new file mode 100644 index 0000000..a8a0230 --- /dev/null +++ b/src/arch/armv7/include/stdint.h @@ -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 */ diff --git a/src/arch/armv7/include/system.h b/src/arch/armv7/include/system.h new file mode 100644 index 0000000..2c7c9a5 --- /dev/null +++ b/src/arch/armv7/include/system.h @@ -0,0 +1,66 @@ +/* FIXME(dhendrix): This is split out from asm/system.h. */ +#ifndef SYSTEM_H_ +#define SYSTEM_H_ + +#include <asm/system.h> + +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 /* SYSTEM_H_ */ diff --git a/src/arch/armv7/include/uapi/asm/hwcap.h b/src/arch/armv7/include/uapi/asm/hwcap.h new file mode 100644 index 0000000..f254f65 --- /dev/null +++ b/src/arch/armv7/include/uapi/asm/hwcap.h @@ -0,0 +1,29 @@ +#ifndef _UAPI__ASMARM_HWCAP_H +#define _UAPI__ASMARM_HWCAP_H + +/* + * HWCAP flags - for elf_hwcap (in kernel) and AT_HWCAP + */ +#define HWCAP_SWP (1 << 0) +#define HWCAP_HALF (1 << 1) +#define HWCAP_THUMB (1 << 2) +#define HWCAP_26BIT (1 << 3) /* Play it safe */ +#define HWCAP_FAST_MULT (1 << 4) +#define HWCAP_FPA (1 << 5) +#define HWCAP_VFP (1 << 6) +#define HWCAP_EDSP (1 << 7) +#define HWCAP_JAVA (1 << 8) +#define HWCAP_IWMMXT (1 << 9) +#define HWCAP_CRUNCH (1 << 10) +#define HWCAP_THUMBEE (1 << 11) +#define HWCAP_NEON (1 << 12) +#define HWCAP_VFPv3 (1 << 13) +#define HWCAP_VFPv3D16 (1 << 14) +#define HWCAP_TLS (1 << 15) +#define HWCAP_VFPv4 (1 << 16) +#define HWCAP_IDIVA (1 << 17) +#define HWCAP_IDIVT (1 << 18) +#define HWCAP_IDIV (HWCAP_IDIVA | HWCAP_IDIVT) + + +#endif /* _UAPI__ASMARM_HWCAP_H */ diff --git a/src/arch/armv7/include/uapi/asm/ptrace.h b/src/arch/armv7/include/uapi/asm/ptrace.h new file mode 100644 index 0000000..96ee092 --- /dev/null +++ b/src/arch/armv7/include/uapi/asm/ptrace.h @@ -0,0 +1,138 @@ +/* + * arch/arm/include/asm/ptrace.h + * + * Copyright (C) 1996-2003 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. + */ +#ifndef _UAPI__ASM_ARM_PTRACE_H +#define _UAPI__ASM_ARM_PTRACE_H + +#include <asm/hwcap.h> + +#define PTRACE_GETREGS 12 +#define PTRACE_SETREGS 13 +#define PTRACE_GETFPREGS 14 +#define PTRACE_SETFPREGS 15 +/* PTRACE_ATTACH is 16 */ +/* PTRACE_DETACH is 17 */ +#define PTRACE_GETWMMXREGS 18 +#define PTRACE_SETWMMXREGS 19 +/* 20 is unused */ +#define PTRACE_OLDSETOPTIONS 21 +#define PTRACE_GET_THREAD_AREA 22 +#define PTRACE_SET_SYSCALL 23 +/* PTRACE_SYSCALL is 24 */ +#define PTRACE_GETCRUNCHREGS 25 +#define PTRACE_SETCRUNCHREGS 26 +#define PTRACE_GETVFPREGS 27 +#define PTRACE_SETVFPREGS 28 +#define PTRACE_GETHBPREGS 29 +#define PTRACE_SETHBPREGS 30 + +/* + * PSR bits + */ +#define USR26_MODE 0x00000000 +#define FIQ26_MODE 0x00000001 +#define IRQ26_MODE 0x00000002 +#define SVC26_MODE 0x00000003 +#define USR_MODE 0x00000010 +#define FIQ_MODE 0x00000011 +#define IRQ_MODE 0x00000012 +#define SVC_MODE 0x00000013 +#define ABT_MODE 0x00000017 +#define HYP_MODE 0x0000001a +#define UND_MODE 0x0000001b +#define SYSTEM_MODE 0x0000001f +#define MODE32_BIT 0x00000010 +#define MODE_MASK 0x0000001f +#define PSR_T_BIT 0x00000020 +#define PSR_F_BIT 0x00000040 +#define PSR_I_BIT 0x00000080 +#define PSR_A_BIT 0x00000100 +#define PSR_E_BIT 0x00000200 +#define PSR_J_BIT 0x01000000 +#define PSR_Q_BIT 0x08000000 +#define PSR_V_BIT 0x10000000 +#define PSR_C_BIT 0x20000000 +#define PSR_Z_BIT 0x40000000 +#define PSR_N_BIT 0x80000000 + +/* + * Groups of PSR bits + */ +#define PSR_f 0xff000000 /* Flags */ +#define PSR_s 0x00ff0000 /* Status */ +#define PSR_x 0x0000ff00 /* Extension */ +#define PSR_c 0x000000ff /* Control */ + +/* + * ARMv7 groups of PSR bits + */ +#define APSR_MASK 0xf80f0000 /* N, Z, C, V, Q and GE flags */ +#define PSR_ISET_MASK 0x01000010 /* ISA state (J, T) mask */ +#define PSR_IT_MASK 0x0600fc00 /* If-Then execution state mask */ +#define PSR_ENDIAN_MASK 0x00000200 /* Endianness state mask */ + +/* + * Default endianness state + */ +#ifdef CONFIG_CPU_ENDIAN_BE8 +#define PSR_ENDSTATE PSR_E_BIT +#else +#define PSR_ENDSTATE 0 +#endif + +/* + * These are 'magic' values for PTRACE_PEEKUSR that return info about where a + * process is located in memory. + */ +#define PT_TEXT_ADDR 0x10000 +#define PT_DATA_ADDR 0x10004 +#define PT_TEXT_END_ADDR 0x10008 + +#ifndef __ASSEMBLY__ + +/* + * This struct defines the way the registers are stored on the + * stack during a system call. Note that sizeof(struct pt_regs) + * has to be a multiple of 8. + */ +#ifndef __KERNEL__ +struct pt_regs { + long uregs[18]; +}; +#endif /* __KERNEL__ */ + +#define ARM_cpsr uregs[16] +#define ARM_pc uregs[15] +#define ARM_lr uregs[14] +#define ARM_sp uregs[13] +#define ARM_ip uregs[12] +#define ARM_fp uregs[11] +#define ARM_r10 uregs[10] +#define ARM_r9 uregs[9] +#define ARM_r8 uregs[8] +#define ARM_r7 uregs[7] +#define ARM_r6 uregs[6] +#define ARM_r5 uregs[5] +#define ARM_r4 uregs[4] +#define ARM_r3 uregs[3] +#define ARM_r2 uregs[2] +#define ARM_r1 uregs[1] +#define ARM_r0 uregs[0] +#define ARM_ORIG_r0 uregs[17] + +/* + * The size of the user-visible VFP state as seen by PTRACE_GET/SETVFPREGS + * and core dumps. + */ +#define ARM_VFPREGS_SIZE ( 32 * 8 /*fpregs*/ + 4 /*fpscr*/ ) + + +#endif /* __ASSEMBLY__ */ + +#endif /* _UAPI__ASM_ARM_PTRACE_H */ diff --git a/src/arch/armv7/include/utils.h b/src/arch/armv7/include/utils.h new file mode 100644 index 0000000..828b86c --- /dev/null +++ b/src/arch/armv7/include/utils.h @@ -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 diff --git a/src/arch/armv7/ldscript_failover.lb b/src/arch/armv7/ldscript_failover.lb new file mode 100644 index 0000000..9a3b9ae --- /dev/null +++ b/src/arch/armv7/ldscript_failover.lb @@ -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.*) + } +} diff --git a/src/arch/armv7/ldscript_fallback_cbfs.lb b/src/arch/armv7/ldscript_fallback_cbfs.lb new file mode 100644 index 0000000..148f4e3 --- /dev/null +++ b/src/arch/armv7/ldscript_fallback_cbfs.lb @@ -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"); +} diff --git a/src/arch/armv7/lib/Makefile.inc b/src/arch/armv7/lib/Makefile.inc new file mode 100644 index 0000000..bdf6a64 --- /dev/null +++ b/src/arch/armv7/lib/Makefile.inc @@ -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 diff --git a/src/arch/armv7/lib/Makefile.uboot b/src/arch/armv7/lib/Makefile.uboot new file mode 100644 index 0000000..d33d08b --- /dev/null +++ b/src/arch/armv7/lib/Makefile.uboot @@ -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 + +######################################################################### diff --git a/src/arch/armv7/lib/_divsi3.S b/src/arch/armv7/lib/_divsi3.S new file mode 100644 index 0000000..cfbadb2 --- /dev/null +++ b/src/arch/armv7/lib/_divsi3.S @@ -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 diff --git a/src/arch/armv7/lib/_udivsi3.S b/src/arch/armv7/lib/_udivsi3.S new file mode 100644 index 0000000..1309802 --- /dev/null +++ b/src/arch/armv7/lib/_udivsi3.S @@ -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 diff --git a/src/arch/armv7/lib/_uldivmod.S b/src/arch/armv7/lib/_uldivmod.S new file mode 100644 index 0000000..65e4fa8 --- /dev/null +++ b/src/arch/armv7/lib/_uldivmod.S @@ -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} diff --git a/src/arch/armv7/lib/bootm.c b/src/arch/armv7/lib/bootm.c new file mode 100644 index 0000000..afe1b70 --- /dev/null +++ b/src/arch/armv7/lib/bootm.c @@ -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; +} diff --git a/src/arch/armv7/lib/c_start.S b/src/arch/armv7/lib/c_start.S new file mode 100644 index 0000000..b6e7462 --- /dev/null +++ b/src/arch/armv7/lib/c_start.S @@ -0,0 +1,9 @@ +.section ".text" +.globl _start +_start: + bl _hardwaremain + +_hardwaremain: .word hardwaremain +@ .word hardwaremain + + diff --git a/src/arch/armv7/lib/cache-cp15.c b/src/arch/armv7/lib/cache-cp15.c new file mode 100644 index 0000000..45963b5 --- /dev/null +++ b/src/arch/armv7/lib/cache-cp15.c @@ -0,0 +1,305 @@ +/* + * (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 <asm/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 diff --git a/src/arch/armv7/lib/cache_v7.c b/src/arch/armv7/lib/cache_v7.c new file mode 100644 index 0000000..13bb59f --- /dev/null +++ b/src/arch/armv7/lib/cache_v7.c @@ -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 diff --git a/src/arch/armv7/lib/div.c b/src/arch/armv7/lib/div.c new file mode 100644 index 0000000..03352dc --- /dev/null +++ b/src/arch/armv7/lib/div.c @@ -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 +} diff --git a/src/arch/armv7/lib/div0.c b/src/arch/armv7/lib/div0.c new file mode 100644 index 0000000..632c247 --- /dev/null +++ b/src/arch/armv7/lib/div0.c @@ -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(); +} diff --git a/src/arch/armv7/lib/div64.S b/src/arch/armv7/lib/div64.S new file mode 100644 index 0000000..44edf48 --- /dev/null +++ b/src/arch/armv7/lib/div64.S @@ -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, + diff --git a/src/arch/armv7/lib/eabi_compat.c b/src/arch/armv7/lib/eabi_compat.c new file mode 100644 index 0000000..5f59892 --- /dev/null +++ b/src/arch/armv7/lib/eabi_compat.c @@ -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) +{ +}; diff --git a/src/arch/armv7/lib/hang_spl.c b/src/arch/armv7/lib/hang_spl.c new file mode 100644 index 0000000..630a57a --- /dev/null +++ b/src/arch/armv7/lib/hang_spl.c @@ -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 (;;); +} diff --git a/src/arch/armv7/lib/id.inc b/src/arch/armv7/lib/id.inc new file mode 100644 index 0000000..4da7024 --- /dev/null +++ b/src/arch/armv7/lib/id.inc @@ -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 diff --git a/src/arch/armv7/lib/id.lds b/src/arch/armv7/lib/id.lds new file mode 100644 index 0000000..9e31ee6 --- /dev/null +++ b/src/arch/armv7/lib/id.lds @@ -0,0 +1,6 @@ +SECTIONS { + . = (0x100000000 - CONFIG_ID_SECTION_OFFSET) - (__id_end - __id_start); + .id (.): { + *(.id) + } +} diff --git a/src/arch/armv7/lib/interrupts.c b/src/arch/armv7/lib/interrupts.c new file mode 100644 index 0000000..6ee3f26 --- /dev/null +++ b/src/arch/armv7/lib/interrupts.c @@ -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 diff --git a/src/arch/armv7/lib/memcpy.S b/src/arch/armv7/lib/memcpy.S new file mode 100644 index 0000000..f655256 --- /dev/null +++ b/src/arch/armv7/lib/memcpy.S @@ -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 diff --git a/src/arch/armv7/lib/memset.S b/src/arch/armv7/lib/memset.S new file mode 100644 index 0000000..0cdf895 --- /dev/null +++ b/src/arch/armv7/lib/memset.S @@ -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 diff --git a/src/arch/armv7/lib/reset.c b/src/arch/armv7/lib/reset.c new file mode 100644 index 0000000..08e6acb --- /dev/null +++ b/src/arch/armv7/lib/reset.c @@ -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; +} diff --git a/src/arch/armv7/lib/romstage_console.c b/src/arch/armv7/lib/romstage_console.c new file mode 100644 index 0000000..ead26f3 --- /dev/null +++ b/src/arch/armv7/lib/romstage_console.c @@ -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; +} diff --git a/src/arch/armv7/lib/syslib.c b/src/arch/armv7/lib/syslib.c new file mode 100644 index 0000000..6f38bf9 --- /dev/null +++ b/src/arch/armv7/lib/syslib.c @@ -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); +} diff --git a/src/arch/armv7/romstage.ld b/src/arch/armv7/romstage.ld new file mode 100644 index 0000000..f0981e5 --- /dev/null +++ b/src/arch/armv7/romstage.ld @@ -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 = 0x4800 } + +/* 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); + } +} diff --git a/src/arch/armv7/start.S b/src/arch/armv7/start.S new file mode 100644 index 0000000..aaee715 --- /dev/null +++ b/src/arch/armv7/start.S @@ -0,0 +1,542 @@ +/* + * 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 + */ + +#include <asm/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 */ diff --git a/src/arch/x86/include/stddef.h b/src/arch/x86/include/stddef.h deleted file mode 100644 index fc89de5..0000000 --- a/src/arch/x86/include/stddef.h +++ /dev/null @@ -1,24 +0,0 @@ -#ifndef I386_STDDEF_H -#define I386_STDDEF_H - -typedef long ptrdiff_t; -#ifndef __SIZE_TYPE__ -#define __SIZE_TYPE__ unsigned long -#endif -typedef __SIZE_TYPE__ size_t; -typedef long ssize_t; - -typedef int wchar_t; -typedef unsigned int wint_t; - -#define NULL ((void *)0) - -#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER) - -#ifdef __PRE_RAM__ -#define ROMSTAGE_CONST const -#else -#define ROMSTAGE_CONST -#endif - -#endif /* I386_STDDEF_H */ diff --git a/src/console/Kconfig b/src/console/Kconfig index f4e3528..117fdb8 100644 --- a/src/console/Kconfig +++ b/src/console/Kconfig @@ -1,18 +1,33 @@ menu "Console" -# TODO: Rename to SERIAL_CONSOLE once Kconfig transition is complete. -config CONSOLE_SERIAL8250 +config SERIAL_CONSOLE bool "Serial port console output" + default y + help + Send coreboot debug output to a serial port + +config CONSOLE_SERIAL8250 + bool "Serial port console output (I/O mapped, 8250-compatible)" + depends on SERIAL_CONSOLE depends on HAVE_UART_IO_MAPPED default y help Send coreboot debug output to an I/O mapped serial port console.
config CONSOLE_SERIAL8250MEM - bool "Serial port console output (memory mapped)" + bool "Serial port console output (memory mapped, 8250-compatible)" + depends on SERIAL_CONSOLE depends on HAVE_UART_MEMORY_MAPPED help Send coreboot debug output to a memory mapped serial port console.
+config CONSOLE_SERIAL_NONSTANDARD_MEM + bool "Serial port console output (memory-mapped, device-specific)" + depends on SERIAL_CONSOLE + depends on HAVE_UART_MEMORY_MAPPED + help + Send coreboot debug output to a memory mapped serial port console + on a device-specific UART. + choice prompt "Serial port" default CONSOLE_SERIAL_COM1 @@ -50,7 +65,7 @@ config TTYS0_BASE choice prompt "Baud rate" default CONSOLE_SERIAL_115200 - depends on CONSOLE_SERIAL8250 || CONSOLE_SERIAL8250MEM + depends on SERIAL_CONSOLE
config CONSOLE_SERIAL_115200 bool "115200" @@ -75,6 +90,7 @@ config CONSOLE_SERIAL_9600
endchoice
+#FIXME(dhendrix): Change name to SERIAL_BAUD? (Stefan sayz: yes!!) config TTYS0_BAUD int default 115200 if CONSOLE_SERIAL_115200 diff --git a/src/cpu/Kconfig b/src/cpu/Kconfig index 986c68a..383ba79 100644 --- a/src/cpu/Kconfig +++ b/src/cpu/Kconfig @@ -1,3 +1,12 @@ +# Warning: This file is included whether or not the if is here. +# The if controls how the evaluation occurs. +# (See also src/Kconfig) +if ARCH_ARMV7 + +source src/cpu/samsung/Kconfig + +endif # ARCH_ARM + if ARCH_X86
source src/cpu/amd/Kconfig diff --git a/src/cpu/Makefile.inc b/src/cpu/Makefile.inc index 938a8df..93b16ae 100644 --- a/src/cpu/Makefile.inc +++ b/src/cpu/Makefile.inc @@ -3,6 +3,7 @@ ################################################################################ subdirs-y += amd subdirs-y += intel +subdirs-y += samsung subdirs-y += via
################################################################################ diff --git a/src/cpu/samsung/Kconfig b/src/cpu/samsung/Kconfig new file mode 100644 index 0000000..3a14ab8 --- /dev/null +++ b/src/cpu/samsung/Kconfig @@ -0,0 +1,46 @@ +config CPU_SAMSUNG_EXYNOS + bool + default n + +config CPU_SAMSUNG_EXYNOS5 + depends on ARCH_ARMV7 + select CPU_SAMSUNG_EXYNOS + bool + default n + +config SKIP_LOWLEVEL_INIT + bool "Skip low-level init" + default n + help + Certain functions (ie PLL init) and processor features may already be + handled by masked ROM code. + +config IRAM_BOTTOM + hex + default 0x02020000 + +# FIXME(dhendrix): 0x02050000 was in the u-boot sources, but the docs say the +# iRAM range is 0x0202_0000 - 0x0207_7fff (352KB). +#config IRAM_TOP +# hex +# default 0x02050000 +config IRAM_TOP + hex + default 0x02077fff + +config SYS_INIT_SP_ADDR + hex + default 0x0204F800 + +config IRAM_STACK + hex + default SYS_INIT_SP_ADDR + +# FIXME(dhendrix): what should this really be? +config XIP_ROM_SIZE + hex + default 0x20000 + +if CPU_SAMSUNG_EXYNOS5 +source src/cpu/samsung/exynos5250/Kconfig +endif diff --git a/src/cpu/samsung/Makefile.inc b/src/cpu/samsung/Makefile.inc new file mode 100644 index 0000000..b6fcd4e --- /dev/null +++ b/src/cpu/samsung/Makefile.inc @@ -0,0 +1,5 @@ +subdirs-$(CONFIG_CPU_SAMSUNG_EXYNOS5) += exynos5-common +subdirs-$(CONFIG_CPU_SAMSUNG_EXYNOS5) += exynos5250 + +# S5P is a predecessor to Exynos +subdirs-$(CONFIG_CPU_SAMSUNG_EXYNOS) += s5p-common diff --git a/src/cpu/samsung/exynos5-common/Makefile.inc b/src/cpu/samsung/exynos5-common/Makefile.inc new file mode 100644 index 0000000..cad6cb3 --- /dev/null +++ b/src/cpu/samsung/exynos5-common/Makefile.inc @@ -0,0 +1,2 @@ +#romstage-y += soc.c +romstage-y += spl_boot.c diff --git a/src/cpu/samsung/exynos5-common/soc.c b/src/cpu/samsung/exynos5-common/soc.c new file mode 100644 index 0000000..e73fd33 --- /dev/null +++ b/src/cpu/samsung/exynos5-common/soc.c @@ -0,0 +1,30 @@ +/* + * Copyright (c) 2010 Samsung Electronics. + * Minkyu Kang mk7.kang@samsung.com + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +#include <common.h> +#include <arch/io.h> + +void reset_cpu(unsigned long addr) +{ + writel(0x1, samsung_get_base_swreset()); +} diff --git a/src/cpu/samsung/exynos5-common/spl_boot.c b/src/cpu/samsung/exynos5-common/spl_boot.c new file mode 100644 index 0000000..258f4ae --- /dev/null +++ b/src/cpu/samsung/exynos5-common/spl_boot.c @@ -0,0 +1,460 @@ +/* + * Copyright (C) 2011 Samsung Electronics + * + * 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): pulled in a lot of extra crap such as partition and string + libs*/ +#include <assert.h> +#include <common.h> +#include <stdlib.h> +#include <string.h> + +#include <console/console.h> +#include <console/loglevel.h> +//#include <asm/arch/board.h> + +#include <config.h> +#include <spi.h> +#if 0 +#include <asm/arch/clock.h> +#include <asm/arch-exynos/spi.h> +#include <asm/arch/pinmux.h> +#include <asm/arch/power.h> +#endif +#include <arch/hlt.h> +#include <cpu/samsung/exynos5250/clk.h> +#include <cpu/samsung/exynos5250/cpu.h> +#include <cpu/samsung/exynos5250/periph.h> +#include <cpu/samsung/exynos5250/pinmux.h> +#include <cpu/samsung/exynos5250/power.h> +#include <cpu/samsung/exynos5250/spi.h> + +#include <cpu/samsung/exynos-common/cpu.h> +#include <cpu/samsung/exynos-common/exynos5-common.h> + +//#include <asm/system.h> +#include <system.h> + +#include <arch/io.h> +#include <arch/types.h> + +/* FIXME(dhendrix): clean out u-boot global data stuff */ +//DECLARE_GLOBAL_DATA_PTR; + +#define OM_STAT (0x1f << 1) + +/** + * Copy data from SD or MMC device to RAM. + * + * @param offset Block offset of the data + * @param nblock Number of blocks + * @param dst Destination address + * @return 1 = True or 0 = False + */ +typedef u32 (*mmc_copy_func_t)(u32 offset, u32 nblock, u32 dst); + +/** + * Copy data from SPI flash to RAM. + * + * @param offset Block offset of the data + * @param nblock Number of blocks + * @param dst Destination address + * @return 1 = True or 0 = False + */ +typedef u32 (*spi_copy_func_t)(u32 offset, u32 nblock, u32 dst); + + +/** + * Copy data through USB. + * + * @return 1 = True or 0 = False + */ +typedef u32 (*usb_copy_func_t)(void); + +/* + * Set/clear program flow prediction and return the previous state. + */ +static int config_branch_prediction(int set_cr_z) +{ + unsigned int cr; + + /* System Control Register: 11th bit Z Branch prediction enable */ + cr = get_cr(); + set_cr(set_cr_z ? cr | CR_Z : cr & ~CR_Z); + + return cr & CR_Z; +} + +#if 0 +static void spi_rx_tx(struct exynos_spi *regs, int todo, + void *dinp, void const *doutp, int i) +{ + uint *rxp = (uint *)(dinp + (i * (32 * 1024))); + int rx_lvl, tx_lvl; + uint out_bytes, in_bytes; + + out_bytes = in_bytes = todo; + setbits_le32(®s->ch_cfg, SPI_CH_RST); + clrbits_le32(®s->ch_cfg, SPI_CH_RST); + writel(((todo * 8) / 32) | SPI_PACKET_CNT_EN, ®s->pkt_cnt); + + while (in_bytes) { + uint32_t spi_sts; + int temp; + + spi_sts = readl(®s->spi_sts); + rx_lvl = ((spi_sts >> 15) & 0x7f); + tx_lvl = ((spi_sts >> 6) & 0x7f); + while (tx_lvl < 32 && out_bytes) { + temp = 0xffffffff; + writel(temp, ®s->tx_data); + out_bytes -= 4; + tx_lvl += 4; + } + while (rx_lvl >= 4 && in_bytes) { + temp = readl(®s->rx_data); + if (rxp) + *rxp++ = temp; + in_bytes -= 4; + rx_lvl -= 4; + } + } +} +#endif + +/* FIXME(dhendrix): feels like exynos_spi_copy should go somewhere else... */ +#if 0 +/** + * Copy uboot from spi flash to RAM + * + * @parma uboot_size size of u-boot to copy + */ +static void exynos_spi_copy(unsigned int uboot_size) +{ + int upto, todo; + int i; +// struct exynos_spi *regs = (struct exynos_spi *)samsung_get_base_spi1(); + struct exynos_spi *regs = (struct exynos_spi *)0x12d30000; + + clock_set_rate(PERIPH_ID_SPI1, 50000000); /* set spi clock to 50Mhz */ + /* set the spi1 GPIO */ + exynos_pinmux_config(PERIPH_ID_SPI1, PINMUX_FLAG_NONE); + + /* set pktcnt and enable it */ + writel(4 | SPI_PACKET_CNT_EN, ®s->pkt_cnt); + /* set FB_CLK_SEL */ + writel(SPI_FB_DELAY_180, ®s->fb_clk); + /* set CH_WIDTH and BUS_WIDTH as word */ + setbits_le32(®s->mode_cfg, SPI_MODE_CH_WIDTH_WORD | + SPI_MODE_BUS_WIDTH_WORD); + clrbits_le32(®s->ch_cfg, SPI_CH_CPOL_L); /* CPOL: active high */ + + /* clear rx and tx channel if set priveously */ + clrbits_le32(®s->ch_cfg, SPI_RX_CH_ON | SPI_TX_CH_ON); + + setbits_le32(®s->swap_cfg, SPI_RX_SWAP_EN | + SPI_RX_BYTE_SWAP | + SPI_RX_HWORD_SWAP); + + /* do a soft reset */ + setbits_le32(®s->ch_cfg, SPI_CH_RST); + clrbits_le32(®s->ch_cfg, SPI_CH_RST); + + /* now set rx and tx channel ON */ + setbits_le32(®s->ch_cfg, SPI_RX_CH_ON | SPI_TX_CH_ON | SPI_CH_HS_EN); + clrbits_le32(®s->cs_reg, SPI_SLAVE_SIG_INACT); /* CS low */ + + /* Send read instruction (0x3h) followed by a 24 bit addr */ + writel((SF_READ_DATA_CMD << 24) | SPI_FLASH_UBOOT_POS, ®s->tx_data); + + /* waiting for TX done */ + while (!(readl(®s->spi_sts) & SPI_ST_TX_DONE)); + + for (upto = 0, i = 0; upto < uboot_size; upto += todo, i++) { + todo = MIN(uboot_size - upto, (1 << 15)); + spi_rx_tx(regs, todo, (void *)(CONFIG_SYS_TEXT_BASE), + (void *)(SPI_FLASH_UBOOT_POS), i); + } + + setbits_le32(®s->cs_reg, SPI_SLAVE_SIG_INACT);/* make the CS high */ + + /* + * Let put controller mode to BYTE as + * SPI driver does not support WORD mode yet + */ + clrbits_le32(®s->mode_cfg, SPI_MODE_CH_WIDTH_WORD | + SPI_MODE_BUS_WIDTH_WORD); + writel(0, ®s->swap_cfg); + + /* + * Flush spi tx, rx fifos and reset the SPI controller + * and clear rx/tx channel + */ + clrsetbits_le32(®s->ch_cfg, SPI_CH_HS_EN, SPI_CH_RST); + clrbits_le32(®s->ch_cfg, SPI_CH_RST); + clrbits_le32(®s->ch_cfg, SPI_TX_CH_ON | SPI_RX_CH_ON); +} +#endif + +/* Copy U-Boot image to RAM */ +static void copy_uboot_to_ram(void) +{ + unsigned int sec_boot_check; + unsigned int uboot_size = CONFIG_COREBOOT_ROMSIZE_KB_4096; + int is_cr_z_set; + enum boot_mode boot_mode = BOOT_MODE_OM; + mmc_copy_func_t mmc_copy; + + usb_copy_func_t usb_copy; + +#if 0 + uboot_size = exynos_get_uboot_size(); + boot_mode = exynos_get_boot_device(); +#endif + + if (boot_mode == BOOT_MODE_OM) { + /* Read iRAM location to check for secondary USB boot mode */ + sec_boot_check = readl(EXYNOS_IRAM_SECONDARY_BASE); + if (sec_boot_check == EXYNOS_USB_SECONDARY_BOOT) + boot_mode = BOOT_MODE_USB; + } + debug("U-Boot size %u\n", uboot_size); + + if (boot_mode == BOOT_MODE_OM) + boot_mode = readl(EXYNOS_POWER_BASE) & OM_STAT; + + switch (boot_mode) { +#if defined(CONFIG_EXYNOS_SPI_BOOT) + case BOOT_MODE_SERIAL: + /* let us our own function to copy u-boot from SF */ + exynos_spi_copy(uboot_size); + break; +#endif + case BOOT_MODE_MMC: + mmc_copy = *(mmc_copy_func_t *)EXYNOS_COPY_MMC_FNPTR_ADDR; + assert(!(uboot_size & 511)); + mmc_copy(BL2_START_OFFSET, uboot_size / 512, + CONFIG_SYS_TEXT_BASE); + break; + case BOOT_MODE_USB: + /* + * iROM needs program flow prediction to be disabled + * before copy from USB device to RAM + */ + is_cr_z_set = config_branch_prediction(0); + usb_copy = *(usb_copy_func_t *) + EXYNOS_COPY_USB_FNPTR_ADDR; + usb_copy(); + config_branch_prediction(is_cr_z_set); + break; + default: + printk(BIOS_ERR, "Invalid boot mode selection\n"); + hlt(); + break; + } + debug("U-Boot copied\n"); +} + +#if 0 +/** + * Set up the U-Boot global_data pointer + * + * This sets the address of the global data, and sets up basic values. + * + * @param gdp Value to give to gd + */ +static void setup_global_data(gd_t *gdp) +{ + gd = gdp; + memzero((void *)gd, sizeof(gd_t)); + gd->flags |= GD_FLG_RELOC; + gd->baudrate = CONFIG_BAUDRATE; + gd->have_console = 1; +} +#endif + +#if 0 +/* Tell the loaded U-Boot that it was loaded from SPL */ +static void exynos5_set_spl_marker(void) +{ + uint32_t *marker = (uint32_t *)CONFIG_SPL_MARKER; + + *marker = EXYNOS5_SPL_MARKER; +} +#endif + +/* Board-specific call to see if wakeup is allowed. */ +static int __def_board_wakeup_permitted(void) +{ + return 1; +} +int board_wakeup_permitted(void) + __attribute__((weak, alias("__def_board_wakeup_permitted"))); + +void board_init_f(unsigned long bootflag) +{ + /* + * The gd struct is only needed for serial initialization. Since this + * function is called in SPL u-boot. We store the gd struct in the + * stack instead of the default memory region which may not be + * initialized. + */ +// __attribute__((aligned(8))) gd_t local_gd; +// __attribute__((noreturn)) void (*uboot)(void); + +// exynos5_set_spl_marker(); +// setup_global_data(&local_gd); + + /* + * Init subsystems, and resume if required. For a normal boot this + * will set up the UART and display a message. + */ + if (lowlevel_init_subsystems()) { + if (!board_wakeup_permitted()) + power_reset(); + power_exit_wakeup(); + } + +// printk(BIOS_INFO, "\n\nU-Boot SPL, board rev %u\n", board_get_revision()); + + copy_uboot_to_ram(); + /* Jump to U-Boot image */ +// uboot = (void *)CONFIG_SYS_TEXT_BASE; +// uboot(); + /* Never returns Here */ +// printk(BIOS_ERR, "%s: u-boot jump failed", __func__); + printk(BIOS_INFO, "%s: we should not be here...", __func__); + hlt(); +} + +/* Place Holders */ +void board_init_r(gd_t *id, ulong dest_addr) +{ + /* Function attribute is no-return */ + /* This Function never executes */ + while (1) + ; +} + +//void save_boot_params(u32 r0, u32 r1, u32 r2, u32 r3) {} + +#if 0 +/* + * The following functions are required when linking console library to SPL. + * + * Enabling UART in SPL u-boot requires console library. But some + * functions we needed in the console library depends on a bunch + * of library in libgeneric, like lib/ctype.o, lib/div64.o, lib/string.o, + * and lib/vsprintf.o. Adding them makes the SPL u-boot too large and not + * fit into the expected size. + * + * So we mock these functions in SPL, i.e. vsprintf(), panic(), etc., + * in order to cut its dependency. + */ +int vsprintf(char *buf, const char *fmt, va_list args) +{ + char *str = buf, *s; + ulong u; + + /* + * We won't implement all full functions of vsprintf(). + * We only implement %s and %u, and ignore others and directly use + * the original format string as its result. + */ + + while (*fmt) { + if (*fmt != '%') { + *str++ = *fmt++; + continue; + } + fmt++; + switch (*fmt) { + case '%': + *str++ = *fmt++; + break; + case 's': + fmt++; + s = va_arg(args, char *); + while (*s) + *str++ = *s++; + break; + case 'u': + fmt++; + u = va_arg(args, ulong); + s = simple_itoa(u); + while (*s) + *str++ = *s++; + break; + default: + /* Print the original string for unsupported formats */ + *str++ = '%'; + *str++ = *fmt++; + } + } + *str = '\0'; + return str - buf; +} +#endif + +#if 0 +void panic(const char *fmt, ...) +{ + va_list args; + va_start(args, fmt); + vprintf(fmt, args); + putc('\n'); + va_end(args); +#if defined(CONFIG_PANIC_HANG) + hang(); +#else + udelay(100000); /* allow messages to go out */ + do_reset(NULL, 0, 0, NULL); +#endif + while (1) + ; +} +#endif + +#if 0 +void __assert_fail(const char *assertion, const char *file, unsigned line, + const char *function) +{ + /* This will not return */ + panic("%s:%u: %s: Assertion `%s' failed.", file, line, function, + assertion); +} +#endif + +#if 0 +char *simple_itoa(ulong i) +{ + /* 21 digits plus null terminator, good for 64-bit or smaller ints */ + static char local[22] __attribute__((section(".data"))); + char *p = &local[21]; + + *p-- = '\0'; + do { + *p-- = '0' + i % 10; + i /= 10; + } while (i > 0); + return p + 1; +} +#endif diff --git a/src/cpu/samsung/exynos5250/Kconfig b/src/cpu/samsung/exynos5250/Kconfig new file mode 100644 index 0000000..8d4ba2d --- /dev/null +++ b/src/cpu/samsung/exynos5250/Kconfig @@ -0,0 +1,28 @@ +config EXYNOS_ACE_SHA + bool + default n + +config SATA_AHCI + bool + default n + +config SPL_BUILD + bool + default n + +config SYS_TEXT_BASE + hex "Executable code section" + default 0x43e00000 + +config SYS_SDRAM_BASE + hex "SDRAM base address" + default 0x40000000 + +#FIXME(dhendrix, reinauer): re-visit this RAMBASE/RAMTOP stuff... +config RAMBASE + hex + default SYS_SDRAM_BASE +# according to stefan, this is RAMBASE + 1M. +config RAMTOP + hex + default 0x40100000 diff --git a/src/cpu/samsung/exynos5250/Makefile.inc b/src/cpu/samsung/exynos5250/Makefile.inc new file mode 100644 index 0000000..556631a --- /dev/null +++ b/src/cpu/samsung/exynos5250/Makefile.inc @@ -0,0 +1,32 @@ +romstage-y += clock.c +romstage-y += clock_init.c +romstage-y += exynos_cache.c +romstage-y += lowlevel_init.S +romstage-y += lowlevel_init_c.c +romstage-y += pinmux.c +romstage-y += power.c +romstage-y += soc.c +romstage-y += uart.c + +#ramstage-y += clock.c +#ramstage-y += clock_init.c +#ramstage-y += power.c +#ramstage-y += uart.c +##ramstage-y += spl.c +#ramstage-y += pinmux.c +##ramstage-y += tzpc_init.c +ramstage-y += clock.c +ramstage-y += clock_init.c +ramstage-y += exynos_cache.c +ramstage-y += lowlevel_init.S +ramstage-y += lowlevel_init_c.c +ramstage-y += pinmux.c +ramstage-y += power.c +ramstage-y += soc.c +ramstage-y += uart.c + +#ramstage-$(CONFIG_EXYNOS_ACE_SHA) += ace_sha.c +#ramstage-$(CONFIG_SATA_AHCI) += sata.c +ramstage-$(CONFIG_SPL_BUILD) += lowlevel_init_c.c +ramstage-$(CONFIG_SPL_BUILD) += dmc_common.c +ramstage-$(CONFIG_SPL_BUILD) += dmc_init_ddr3.c diff --git a/src/cpu/samsung/exynos5250/ace_sha.c b/src/cpu/samsung/exynos5250/ace_sha.c new file mode 100644 index 0000000..2715a03 --- /dev/null +++ b/src/cpu/samsung/exynos5250/ace_sha.c @@ -0,0 +1,118 @@ +/* + * Advanced Crypto Engine - SHA Firmware + * + * Copyright (c) 2012 Samsung Electronics + * + * 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/arch/ace_sha.h> +#include <asm/arch/ace_sfr.h> + +/* Maximum input data size is 8 MB. Timeout observed for data size above 8MB */ +#define TIMEOUT_MS 100 + +#define SHA1_DIGEST_LEN 20 +#define SHA256_DIGEST_LEN 32 + +/* SHA1 value for the message of zero length */ +static const unsigned char sha1_digest_emptymsg[SHA1_DIGEST_LEN] = { + 0xDA, 0x39, 0xA3, 0xEE, 0x5E, 0x6B, 0x4B, 0x0D, + 0x32, 0x55, 0xBF, 0xFF, 0x95, 0x60, 0x18, 0x90, + 0xAF, 0xD8, 0x07, 0x09}; + +/* SHA256 value for the message of zero length */ +static const unsigned char sha256_digest_emptymsg[SHA256_DIGEST_LEN] = { + 0xE3, 0xB0, 0xC4, 0x42, 0x98, 0xFC, 0x1C, 0x14, + 0x9A, 0xFB, 0xF4, 0xC8, 0x99, 0x6F, 0xB9, 0x24, + 0x27, 0xAE, 0x41, 0xE4, 0x64, 0x9B, 0x93, 0x4C, + 0xA4, 0x95, 0x99, 0x1B, 0x78, 0x52, 0xB8, 0x55}; + +int ace_sha_hash_digest( + unsigned char *pout, unsigned char *pbuf, + unsigned int buf_len, unsigned int hash_type) +{ + unsigned int i, reg, len; + unsigned int *pdigest; + ulong start; + struct exynos_ace_sfr *ace_sha_reg = + (struct exynos_ace_sfr *) samsung_get_base_ace_sfr(); + + if (buf_len == 0) { + /* ACE H/W cannot compute hash value for empty string */ + if (hash_type == ACE_SHA_TYPE_SHA1) + memcpy(pout, sha1_digest_emptymsg, SHA1_DIGEST_LEN); + else + memcpy(pout, sha256_digest_emptymsg, SHA256_DIGEST_LEN); + return 0; + } + + /* Flush HRDMA */ + writel(ACE_FC_HRDMACFLUSH_ON, &ace_sha_reg->fc_hrdmac); + writel(ACE_FC_HRDMACFLUSH_OFF, &ace_sha_reg->fc_hrdmac); + + /* Set byte swap of data in */ + writel(ACE_HASH_SWAPDI_ON | ACE_HASH_SWAPDO_ON | ACE_HASH_SWAPIV_ON, + &ace_sha_reg->hash_byteswap); + + /* Select Hash input mux as external source */ + reg = readl(&ace_sha_reg->fc_fifoctrl); + reg = (reg & ~ACE_FC_SELHASH_MASK) | ACE_FC_SELHASH_EXOUT; + writel(reg, &ace_sha_reg->fc_fifoctrl); + + /* Set Hash as SHA1 or SHA256 and start Hash engine */ + reg = (hash_type == ACE_SHA_TYPE_SHA1) ? + ACE_HASH_ENGSEL_SHA1HASH : ACE_HASH_ENGSEL_SHA256HASH; + reg |= ACE_HASH_STARTBIT_ON; + writel(reg, &ace_sha_reg->hash_control); + + /* Enable FIFO mode */ + writel(ACE_HASH_FIFO_ON, &ace_sha_reg->hash_fifo_mode); + + /* Set message length */ + writel(buf_len, &ace_sha_reg->hash_msgsize_low); + writel(0, &ace_sha_reg->hash_msgsize_high); + + /* Set HRDMA */ + writel((unsigned int)pbuf, &ace_sha_reg->fc_hrdmas); + writel(buf_len, &ace_sha_reg->fc_hrdmal); + + start = get_timer(0); + + while ((readl(&ace_sha_reg->hash_status) & ACE_HASH_MSGDONE_MASK) == + ACE_HASH_MSGDONE_OFF) { + + if (get_timer(start) > TIMEOUT_MS) { + debug("%s: Timeout waiting for ACE\n", __func__); + return -1; + } + } + + /* Clear MSG_DONE bit */ + writel(ACE_HASH_MSGDONE_ON, &ace_sha_reg->hash_status); + + /* Read hash result */ + pdigest = (unsigned int *)pout; + len = (hash_type == ACE_SHA_TYPE_SHA1) ? 5 : 8; + + for (i = 0; i < len ; i++) + pdigest[i] = readl(&ace_sha_reg->hash_result[i]); + + /* Clear HRDMA pending bit */ + writel(ACE_FC_HRDMA, &ace_sha_reg->fc_intpend); + + return 0; +} diff --git a/src/cpu/samsung/exynos5250/clock.c b/src/cpu/samsung/exynos5250/clock.c new file mode 100644 index 0000000..dfe2089 --- /dev/null +++ b/src/cpu/samsung/exynos5250/clock.c @@ -0,0 +1,610 @@ +/* + * Copyright (C) 2010 Samsung Electronics + * Minkyu Kang mk7.kang@samsung.com + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +#include <common.h> +#include <console/console.h> +#include <stdlib.h> +//#include <fdtdec.h> +#include <arch/io.h> +//#include <asm/arch/clock.h> +//#include <asm/arch/clk.h> +#include <cpu/samsung/exynos-common/clk.h> +#include <cpu/samsung/exynos5250/clk.h> +#include <cpu/samsung/exynos5250/cpu.h> +#include <cpu/samsung/exynos5250/periph.h> +#include <cpu/samsung/s5p-common/clk.h> + +/* input clock of PLL: SMDK5250 has 24MHz input clock */ +#define CONFIG_SYS_CLK_FREQ 24000000 + + +/* src_bit div_bit prediv_bit */ +static struct clk_bit_info clk_bit_info[PERIPH_ID_COUNT] = { + {0, 4, 0, -1}, + {4, 4, 4, -1}, + {8, 4, 8, -1}, + {12, 4, 12, -1}, + {0, 4, 0, 8}, + {4, 4, 16, 24}, + {8, 4, 0, 8}, + {12, 4, 16, 24}, + {-1, -1, -1, -1}, + {16, 4, 0, 8}, /* PERIPH_ID_SROMC */ + {20, 4, 16, 24}, + {24, 4, 0, 8}, + {0, 4, 0, 4}, + {4, 4, 12, 16}, + {-1, 4, -1, -1}, + {-1, 4, -1, -1}, + {-1, 4, 24, 0}, + {-1, 4, 24, 0}, + {-1, 4, 24, 0}, + {-1, 4, 24, 0}, + {-1, 4, 24, 0}, + {-1, 4, 24, 0}, + {-1, 4, 24, 0}, + {-1, 4, 24, 0}, + {24, 4, 0, -1}, + {24, 4, 0, -1}, + {24, 4, 0, -1}, + {24, 4, 0, -1}, + {24, 4, 0, -1}, + {-1, -1, -1, -1}, + {-1, -1, -1, -1}, + {-1, -1, -1, -1}, /* PERIPH_ID_I2S1 */ + {24, 1, 20, -1}, /* PERIPH_ID_SATA */ +}; + +/* Epll Clock division values to achive different frequency output */ +static struct st_epll_con_val epll_div[] = { + { 192000000, 0, 48, 3, 1, 0 }, + { 180000000, 0, 45, 3, 1, 0 }, + { 73728000, 1, 73, 3, 3, 47710 }, + { 67737600, 1, 90, 4, 3, 20762 }, + { 49152000, 0, 49, 3, 3, 9961 }, + { 45158400, 0, 45, 3, 3, 10381 }, + { 180633600, 0, 45, 3, 1, 10381 } +}; + +/* exynos5: return pll clock frequency */ +unsigned long get_pll_clk(int pllreg) +{ + struct exynos5_clock *clk = + (struct exynos5_clock *)samsung_get_base_clock(); + unsigned long r, m, p, s, k = 0, mask, fout; + unsigned int freq; + + switch (pllreg) { + case APLL: + r = readl(&clk->apll_con0); + break; + case BPLL: + r = readl(&clk->bpll_con0); + break; + case MPLL: + r = readl(&clk->mpll_con0); + break; + case EPLL: + r = readl(&clk->epll_con0); + k = readl(&clk->epll_con1); + break; + case VPLL: + r = readl(&clk->vpll_con0); + k = readl(&clk->vpll_con1); + break; + default: + printk(BIOS_DEBUG, "Unsupported PLL (%d)\n", pllreg); + return 0; + } + + /* + * APLL_CON: MIDV [25:16] + * MPLL_CON: MIDV [25:16] + * EPLL_CON: MIDV [24:16] + * VPLL_CON: MIDV [24:16] + */ + if (pllreg == APLL || pllreg == BPLL || pllreg == MPLL) + mask = 0x3ff; + else + mask = 0x1ff; + + m = (r >> 16) & mask; + + /* PDIV [13:8] */ + p = (r >> 8) & 0x3f; + /* SDIV [2:0] */ + s = r & 0x7; + + freq = CONFIG_SYS_CLK_FREQ; + + if (pllreg == EPLL) { + k = k & 0xffff; + /* FOUT = (MDIV + K / 65536) * FIN / (PDIV * 2^SDIV) */ + fout = (m + k / 65536) * (freq / (p * (1 << s))); + } else if (pllreg == VPLL) { + k = k & 0xfff; + /* FOUT = (MDIV + K / 1024) * FIN / (PDIV * 2^SDIV) */ + fout = (m + k / 1024) * (freq / (p * (1 << s))); + } else { + /* FOUT = MDIV * FIN / (PDIV * 2^SDIV) */ + fout = m * (freq / (p * (1 << s))); + } + + return fout; +} + +unsigned long clock_get_periph_rate(enum periph_id peripheral) +{ + struct exynos5_clock *clk = + (struct exynos5_clock *)samsung_get_base_clock(); + struct clk_bit_info *bit_info = &clk_bit_info[peripheral]; + unsigned long sclk, sub_clk; + unsigned int src, div, sub_div; + + switch (peripheral) { + case PERIPH_ID_UART0: + case PERIPH_ID_UART1: + case PERIPH_ID_UART2: + case PERIPH_ID_UART3: + src = readl(&clk->src_peric0); + div = readl(&clk->div_peric0); + break; + case PERIPH_ID_PWM0: + case PERIPH_ID_PWM1: + case PERIPH_ID_PWM2: + case PERIPH_ID_PWM3: + case PERIPH_ID_PWM4: + src = readl(&clk->src_peric0); + div = readl(&clk->div_peric3); + break; + case PERIPH_ID_SPI0: + case PERIPH_ID_SPI1: + src = readl(&clk->src_peric1); + div = readl(&clk->div_peric1); + break; + case PERIPH_ID_SPI2: + src = readl(&clk->src_peric1); + div = readl(&clk->div_peric2); + break; + case PERIPH_ID_SPI3: + case PERIPH_ID_SPI4: + src = readl(&clk->sclk_src_isp); + div = readl(&clk->sclk_div_isp); + break; + case PERIPH_ID_SATA: + src = readl(&clk->src_fsys); + div = readl(&clk->div_fsys0); + break; + case PERIPH_ID_SDMMC0: + case PERIPH_ID_SDMMC1: + case PERIPH_ID_SDMMC2: + case PERIPH_ID_SDMMC3: + src = readl(&clk->src_fsys); + div = readl(&clk->div_fsys1); + break; + case PERIPH_ID_I2C0: + case PERIPH_ID_I2C1: + case PERIPH_ID_I2C2: + case PERIPH_ID_I2C3: + case PERIPH_ID_I2C4: + case PERIPH_ID_I2C5: + case PERIPH_ID_I2C6: + case PERIPH_ID_I2C7: + sclk = get_pll_clk(MPLL); + sub_div = ((readl(&clk->div_top1) >> bit_info->div_bit) & 0x7) + 1; + div = ((readl(&clk->div_top0) >> bit_info->prediv_bit) & 0x7) + 1; + return (sclk / sub_div) / div; + default: + printk(BIOS_DEBUG, "%s: invalid peripheral %d", __func__, peripheral); + return -1; + }; + + src = (src >> bit_info->src_bit) & ((1 << bit_info->n_src_bits) - 1); + if (peripheral == PERIPH_ID_SATA) { + if (src) + sclk = get_pll_clk(BPLL); + else + sclk = get_pll_clk(MPLL); + } else { + if (src == SRC_MPLL) + sclk = get_pll_clk(MPLL); + else if (src == SRC_EPLL) + sclk = get_pll_clk(EPLL); + else if (src == SRC_VPLL) + sclk = get_pll_clk(VPLL); + else + return 0; + } + + sub_div = (div >> bit_info->div_bit) & 0xf; + sub_clk = sclk / (sub_div + 1); + + if (peripheral == PERIPH_ID_SDMMC0 || peripheral == PERIPH_ID_SDMMC2) { + div = (div >> bit_info->prediv_bit) & 0xff; + return sub_clk / (div + 1); + } + + return sub_clk; +} + +/* exynos5: return ARM clock frequency */ +unsigned long get_arm_clk(void) +{ + struct exynos5_clock *clk = + (struct exynos5_clock *)samsung_get_base_clock(); + unsigned long div; + unsigned long armclk; + unsigned int arm_ratio; + unsigned int arm2_ratio; + + div = readl(&clk->div_cpu0); + + /* ARM_RATIO: [2:0], ARM2_RATIO: [30:28] */ + arm_ratio = (div >> 0) & 0x7; + arm2_ratio = (div >> 28) & 0x7; + + armclk = get_pll_clk(APLL) / (arm_ratio + 1); + armclk /= (arm2_ratio + 1); + + return armclk; +} + +/* exynos5: set the mmc clock */ +void set_mmc_clk(int dev_index, unsigned int div) +{ + struct exynos5_clock *clk = + (struct exynos5_clock *)samsung_get_base_clock(); + unsigned int addr; + unsigned int val; + + /* + * CLK_DIV_FSYS1 + * MMC0_PRE_RATIO [15:8], MMC1_PRE_RATIO [31:24] + * CLK_DIV_FSYS2 + * MMC2_PRE_RATIO [15:8], MMC3_PRE_RATIO [31:24] + */ + if (dev_index < 2) { + addr = (unsigned int)&clk->div_fsys1; + } else { + addr = (unsigned int)&clk->div_fsys2; + dev_index -= 2; + } + + val = readl(addr); + val &= ~(0xff << ((dev_index << 4) + 8)); + val |= (div & 0xff) << ((dev_index << 4) + 8); + writel(val, addr); +} + +void clock_ll_set_pre_ratio(enum periph_id periph_id, unsigned divisor) +{ + struct exynos5_clock *clk = + (struct exynos5_clock *)samsung_get_base_clock(); + unsigned shift; + unsigned mask = 0xff; + u32 *reg; + + /* + * For now we only handle a very small subset of peipherals here. + * Others will need to (and do) mangle the clock registers + * themselves, At some point it is hoped that this function can work + * from a table or calculated register offset / mask. For now this + * is at least better than spreading clock control code around + * U-Boot. + */ + switch (periph_id) { + case PERIPH_ID_SPI0: + reg = &clk->div_peric1; + shift = 8; + break; + case PERIPH_ID_SPI1: + reg = &clk->div_peric1; + shift = 24; + break; + case PERIPH_ID_SPI2: + reg = &clk->div_peric2; + shift = 8; + break; + case PERIPH_ID_SPI3: + reg = &clk->sclk_div_isp; + shift = 4; + break; + case PERIPH_ID_SPI4: + reg = &clk->sclk_div_isp; + shift = 16; + break; + default: + debug("%s: Unsupported peripheral ID %d\n", __func__, + periph_id); + return; + } + clrsetbits_le32(reg, mask << shift, (divisor & mask) << shift); +} + +void clock_ll_set_ratio(enum periph_id periph_id, unsigned divisor) +{ + struct exynos5_clock *clk = + (struct exynos5_clock *)samsung_get_base_clock(); + unsigned shift; + unsigned mask = 0xff; + u32 *reg; + + switch (periph_id) { + case PERIPH_ID_SPI0: + reg = &clk->div_peric1; + shift = 0; + break; + case PERIPH_ID_SPI1: + reg = &clk->div_peric1; + shift = 16; + break; + case PERIPH_ID_SPI2: + reg = &clk->div_peric2; + shift = 0; + break; + case PERIPH_ID_SPI3: + reg = &clk->sclk_div_isp; + shift = 0; + break; + case PERIPH_ID_SPI4: + reg = &clk->sclk_div_isp; + shift = 12; + break; + default: + debug("%s: Unsupported peripheral ID %d\n", __func__, + periph_id); + return; + } + clrsetbits_le32(reg, mask << shift, (divisor & mask) << shift); +} + +/** + * Linearly searches for the most accurate main and fine stage clock scalars + * (divisors) for a specified target frequency and scalar bit sizes by checking + * all multiples of main_scalar_bits values. Will always return scalars up to or + * slower than target. + * + * @param main_scalar_bits Number of main scalar bits, must be > 0 and < 32 + * @param fine_scalar_bits Number of fine scalar bits, must be > 0 and < 32 + * @param input_freq Clock frequency to be scaled in Hz + * @param target_freq Desired clock frequency in Hz + * @param best_fine_scalar Pointer to store the fine stage divisor + * + * @return best_main_scalar Main scalar for desired frequency or -1 if none + * found + */ +static int clock_calc_best_scalar(unsigned int main_scaler_bits, + unsigned int fine_scalar_bits, unsigned int input_rate, + unsigned int target_rate, unsigned int *best_fine_scalar) +{ + int i; + int best_main_scalar = -1; + unsigned int best_error = target_rate; + const unsigned int cap = (1 << fine_scalar_bits) - 1; + const unsigned int loops = 1 << main_scaler_bits; + + debug("Input Rate is %u, Target is %u, Cap is %u\n", input_rate, + target_rate, cap); + + assert(best_fine_scalar != NULL); + assert(main_scaler_bits <= fine_scalar_bits); + + *best_fine_scalar = 1; + + if (input_rate == 0 || target_rate == 0) + return -1; + + if (target_rate >= input_rate) + return 1; + + for (i = 1; i <= loops; i++) { + const unsigned int effective_div = MAX(MIN(input_rate / i / + target_rate, cap), 1); + const unsigned int effective_rate = input_rate / i / + effective_div; + const int error = target_rate - effective_rate; + + debug("%d|effdiv:%u, effrate:%u, error:%d\n", i, effective_div, + effective_rate, error); + + if (error >= 0 && error <= best_error) { + best_error = error; + best_main_scalar = i; + *best_fine_scalar = effective_div; + } + } + + return best_main_scalar; +} + +int clock_set_rate(enum periph_id periph_id, unsigned int rate) +{ + int main; + unsigned int fine; + + switch (periph_id) { + case PERIPH_ID_SPI0: + case PERIPH_ID_SPI1: + case PERIPH_ID_SPI2: + case PERIPH_ID_SPI3: + case PERIPH_ID_SPI4: + main = clock_calc_best_scalar(4, 8, 400000000, rate, &fine); + if (main < 0) { + debug("%s: Cannot set clock rate for periph %d", + __func__, periph_id); + return -1; + } + clock_ll_set_ratio(periph_id, main - 1); + clock_ll_set_pre_ratio(periph_id, fine - 1); + break; + default: + debug("%s: Unsupported peripheral ID %d\n", __func__, + periph_id); + return -1; + } + + return 0; +} + +int clock_set_mshci(enum periph_id peripheral) +{ + struct exynos5_clock *clk = + (struct exynos5_clock *)samsung_get_base_clock(); + u32 *addr; + unsigned int clock; + unsigned int tmp; + unsigned int i; + + /* get mpll clock */ + clock = get_pll_clk(MPLL) / 1000000; + + /* + * CLK_DIV_FSYS1 + * MMC0_PRE_RATIO [15:8], MMC0_RATIO [3:0] + * CLK_DIV_FSYS2 + * MMC2_PRE_RATIO [15:8], MMC2_RATIO [3:0] + */ + switch (peripheral) { + case PERIPH_ID_SDMMC0: + addr = &clk->div_fsys1; + break; + case PERIPH_ID_SDMMC2: + addr = &clk->div_fsys2; + break; + default: + debug("invalid peripheral\n"); + return -1; + } + tmp = readl(addr) & ~0xff0f; + for (i = 0; i <= 0xf; i++) { + if ((clock / (i + 1)) <= 400) { + writel(tmp | i << 0, addr); + break; + } + } + return 0; +} + +#ifdef CONFIG_OF_CONTROL +int clock_decode_periph_id(const void *blob, int node) +{ + enum periph_id id; + + /* + * For now the peripheral ID is directly encoded. Once we have clock + * support in the fdt and properly in exynos U-Boot we may have + * another way of changing the clock. + */ + id = fdtdec_get_int(blob, node, "samsung,periph-id", -1); + assert(id != PERIPH_ID_NONE); + assert(id >= 0 && id < PERIPH_ID_COUNT); + + return id; +} +#endif + +int clock_epll_set_rate(unsigned long rate) +{ + unsigned int epll_con, epll_con_k; + unsigned int i; + unsigned int lockcnt; + unsigned int start; + struct exynos5_clock *clk = + (struct exynos5_clock *)samsung_get_base_clock(); + + epll_con = readl(&clk->epll_con0); + epll_con &= ~((EPLL_CON0_LOCK_DET_EN_MASK << + EPLL_CON0_LOCK_DET_EN_SHIFT) | + EPLL_CON0_MDIV_MASK << EPLL_CON0_MDIV_SHIFT | + EPLL_CON0_PDIV_MASK << EPLL_CON0_PDIV_SHIFT | + EPLL_CON0_SDIV_MASK << EPLL_CON0_SDIV_SHIFT); + + for (i = 0; i < ARRAY_SIZE(epll_div); i++) { + if (epll_div[i].freq_out == rate) + break; + } + + if (i == ARRAY_SIZE(epll_div)) + return -1; + + epll_con_k = epll_div[i].k_dsm << 0; + epll_con |= epll_div[i].en_lock_det << EPLL_CON0_LOCK_DET_EN_SHIFT; + epll_con |= epll_div[i].m_div << EPLL_CON0_MDIV_SHIFT; + epll_con |= epll_div[i].p_div << EPLL_CON0_PDIV_SHIFT; + epll_con |= epll_div[i].s_div << EPLL_CON0_SDIV_SHIFT; + + /* + * Required period ( in cycles) to genarate a stable clock output. + * The maximum clock time can be up to 3000 * PDIV cycles of PLLs + * frequency input (as per spec) + */ + lockcnt = 3000 * epll_div[i].p_div; + + writel(lockcnt, &clk->epll_lock); + writel(epll_con, &clk->epll_con0); + writel(epll_con_k, &clk->epll_con1); + + start = get_timer(0); + + while (!(readl(&clk->epll_con0) & + (0x1 << EXYNOS5_EPLLCON0_LOCKED_SHIFT))) { + if (get_timer(start) > TIMEOUT_EPLL_LOCK) { + printk(BIOS_DEBUG, "%s: Timeout waiting for EPLL lock\n", __func__); + return -1; + } + } + + return 0; +} + +void clock_select_i2s_clk_source(void) +{ + struct exynos5_clock *clk = + (struct exynos5_clock *)samsung_get_base_clock(); + + clrsetbits_le32(&clk->src_peric1, AUDIO1_SEL_MASK, + (CLK_SRC_SCLK_EPLL)); +} + +int clock_set_i2s_clk_prescaler(unsigned int src_frq, unsigned int dst_frq) +{ + struct exynos5_clock *clk = + (struct exynos5_clock *)samsung_get_base_clock(); + unsigned int div ; + + if ((dst_frq == 0) || (src_frq == 0)) { + debug("%s: Invalid requency input for prescaler\n", __func__); + debug("src frq = %d des frq = %d ", src_frq, dst_frq); + return -1; + } + + div = (src_frq / dst_frq); + if (div > AUDIO_1_RATIO_MASK) { + debug("%s: Frequency ratio is out of range\n", __func__); + debug("src frq = %d des frq = %d ", src_frq, dst_frq); + return -1; + } + clrsetbits_le32(&clk->div_peric4, AUDIO_1_RATIO_MASK, + (div & AUDIO_1_RATIO_MASK)); + return 0; +} diff --git a/src/cpu/samsung/exynos5250/clock_init.c b/src/cpu/samsung/exynos5250/clock_init.c new file mode 100644 index 0000000..cecd94f --- /dev/null +++ b/src/cpu/samsung/exynos5250/clock_init.c @@ -0,0 +1,1189 @@ +/* + * Clock setup for SMDK5250 board based on EXYNOS5 + * + * Copyright (C) 2012 Samsung Electronics + * + * 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 + */ + +#if 0 +#include <common.h> +#include <config.h> +//#include <fdtdec.h> +#include <arch/io.h> +#include <asm/arch/board.h> +#include <asm/arch/clk.h> +#include <asm/arch/clock.h> +#include <cpu/samsung/exynos5250/cpu.h> +#include <asm/arch/gpio.h> +#include <asm/arch-exynos/spl.h> +#endif +#include <delay.h> +#include <stdlib.h> +#include <types.h> +#include <system.h> + +#include <console/console.h> + +#include <cpu/samsung/exynos-common/spl.h> +#include <cpu/samsung/exynos5250/clk.h> +#include <cpu/samsung/exynos5250/cpu.h> +#include <cpu/samsung/exynos5250/dmc.h> +#include <cpu/samsung/exynos5250/s5p-dp.h> +#include <cpu/samsung/s5p-common/clk.h> + +#include "clock_init.h" +#include "setup.h" + +//DECLARE_GLOBAL_DATA_PTR; + +struct arm_clk_ratios arm_clk_ratios[] = { + { + .arm_freq_mhz = 600, + + .apll_mdiv = 0xc8, + .apll_pdiv = 0x4, + .apll_sdiv = 0x1, + + .arm2_ratio = 0x0, + .apll_ratio = 0x1, + .pclk_dbg_ratio = 0x1, + .atb_ratio = 0x2, + .periph_ratio = 0x7, + .acp_ratio = 0x7, + .cpud_ratio = 0x1, + .arm_ratio = 0x0, + }, { + .arm_freq_mhz = 800, + + .apll_mdiv = 0x64, + .apll_pdiv = 0x3, + .apll_sdiv = 0x0, + + .arm2_ratio = 0x0, + .apll_ratio = 0x1, + .pclk_dbg_ratio = 0x1, + .atb_ratio = 0x3, + .periph_ratio = 0x7, + .acp_ratio = 0x7, + .cpud_ratio = 0x2, + .arm_ratio = 0x0, + }, { + .arm_freq_mhz = 1000, + + .apll_mdiv = 0x7d, + .apll_pdiv = 0x3, + .apll_sdiv = 0x0, + + .arm2_ratio = 0x0, + .apll_ratio = 0x1, + .pclk_dbg_ratio = 0x1, + .atb_ratio = 0x4, + .periph_ratio = 0x7, + .acp_ratio = 0x7, + .cpud_ratio = 0x2, + .arm_ratio = 0x0, + }, { + .arm_freq_mhz = 1200, + + .apll_mdiv = 0x96, + .apll_pdiv = 0x3, + .apll_sdiv = 0x0, + + .arm2_ratio = 0x0, + .apll_ratio = 0x3, + .pclk_dbg_ratio = 0x1, + .atb_ratio = 0x5, + .periph_ratio = 0x7, + .acp_ratio = 0x7, + .cpud_ratio = 0x3, + .arm_ratio = 0x0, + }, { + .arm_freq_mhz = 1400, + + .apll_mdiv = 0xaf, + .apll_pdiv = 0x3, + .apll_sdiv = 0x0, + + .arm2_ratio = 0x0, + .apll_ratio = 0x3, + .pclk_dbg_ratio = 0x1, + .atb_ratio = 0x6, + .periph_ratio = 0x7, + .acp_ratio = 0x7, + .cpud_ratio = 0x3, + .arm_ratio = 0x0, + }, { + .arm_freq_mhz = 1700, + + .apll_mdiv = 0x1a9, + .apll_pdiv = 0x6, + .apll_sdiv = 0x0, + + .arm2_ratio = 0x0, + .apll_ratio = 0x3, + .pclk_dbg_ratio = 0x1, + .atb_ratio = 0x6, + .periph_ratio = 0x7, + .acp_ratio = 0x7, + .cpud_ratio = 0x3, + .arm_ratio = 0x0, + } +}; + +struct mem_timings mem_timings[] = { + { + .mem_manuf = MEM_MANUF_ELPIDA, + .mem_type = DDR_MODE_DDR3, + .frequency_mhz = 800, + .mpll_mdiv = 0x64, + .mpll_pdiv = 0x3, + .mpll_sdiv = 0x0, + .cpll_mdiv = 0xde, + .cpll_pdiv = 0x4, + .cpll_sdiv = 0x2, + .gpll_mdiv = 0x215, + .gpll_pdiv = 0xc, + .gpll_sdiv = 0x1, + .epll_mdiv = 0x60, + .epll_pdiv = 0x3, + .epll_sdiv = 0x3, + .vpll_mdiv = 0x96, + .vpll_pdiv = 0x3, + .vpll_sdiv = 0x2, + + .bpll_mdiv = 0x64, + .bpll_pdiv = 0x3, + .bpll_sdiv = 0x0, + .use_bpll = 0, + .pclk_cdrex_ratio = 0x5, + .direct_cmd_msr = { + 0x00020018, 0x00030000, 0x00010042, 0x00000d70 + }, + .timing_ref = 0x000000bb, + .timing_row = 0x8c36660f, + .timing_data = 0x3630580b, + .timing_power = 0x41000a44, + .phy0_dqs = 0x08080808, + .phy1_dqs = 0x08080808, + .phy0_dq = 0x08080808, + .phy1_dq = 0x08080808, + .phy0_tFS = 0x4, + .phy1_tFS = 0x4, + .phy0_pulld_dqs = 0xf, + .phy1_pulld_dqs = 0xf, + + .lpddr3_ctrl_phy_reset = 0x1, + .ctrl_start_point = 0x10, + .ctrl_inc = 0x10, + .ctrl_start = 0x1, + .ctrl_dll_on = 0x1, + .ctrl_ref = 0x8, + + .ctrl_force = 0x1a, + .ctrl_rdlat = 0x0b, + .ctrl_bstlen = 0x08, + + .fp_resync = 0x8, + .iv_size = 0x7, + .dfi_init_start = 1, + .aref_en = 1, + + .rd_fetch = 0x3, + + .zq_mode_dds = 0x7, + .zq_mode_term = 0x1, + .zq_mode_noterm = 0, + + /* + * Dynamic Clock: Always Running + * Memory Burst length: 8 + * Number of chips: 1 + * Memory Bus width: 32 bit + * Memory Type: DDR3 + * Additional Latancy for PLL: 0 Cycle + */ + .memcontrol = DMC_MEMCONTROL_CLK_STOP_DISABLE | + DMC_MEMCONTROL_DPWRDN_DISABLE | + DMC_MEMCONTROL_DPWRDN_ACTIVE_PRECHARGE | + DMC_MEMCONTROL_TP_DISABLE | + DMC_MEMCONTROL_DSREF_ENABLE | + DMC_MEMCONTROL_ADD_LAT_PALL_CYCLE(0) | + DMC_MEMCONTROL_MEM_TYPE_DDR3 | + DMC_MEMCONTROL_MEM_WIDTH_32BIT | + DMC_MEMCONTROL_NUM_CHIP_1 | + DMC_MEMCONTROL_BL_8 | + DMC_MEMCONTROL_PZQ_DISABLE | + DMC_MEMCONTROL_MRR_BYTE_7_0, + .memconfig = DMC_MEMCONFIGx_CHIP_MAP_INTERLEAVED | + DMC_MEMCONFIGx_CHIP_COL_10 | + DMC_MEMCONFIGx_CHIP_ROW_15 | + DMC_MEMCONFIGx_CHIP_BANK_8, + .membaseconfig0 = DMC_MEMBASECONFIG_VAL(0x40), + .membaseconfig1 = DMC_MEMBASECONFIG_VAL(0x80), + .prechconfig_tp_cnt = 0xff, + .dpwrdn_cyc = 0xff, + .dsref_cyc = 0xffff, + .concontrol = DMC_CONCONTROL_DFI_INIT_START_DISABLE | + DMC_CONCONTROL_TIMEOUT_LEVEL0 | + DMC_CONCONTROL_RD_FETCH_DISABLE | + DMC_CONCONTROL_EMPTY_DISABLE | + DMC_CONCONTROL_AREF_EN_DISABLE | + DMC_CONCONTROL_IO_PD_CON_DISABLE, + .dmc_channels = 2, + .chips_per_channel = 2, + .chips_to_configure = 1, + .send_zq_init = 1, + .impedance = IMP_OUTPUT_DRV_30_OHM, + .gate_leveling_enable = 0, + }, { + .mem_manuf = MEM_MANUF_SAMSUNG, + .mem_type = DDR_MODE_DDR3, + .frequency_mhz = 800, + .mpll_mdiv = 0x64, + .mpll_pdiv = 0x3, + .mpll_sdiv = 0x0, + .cpll_mdiv = 0xde, + .cpll_pdiv = 0x4, + .cpll_sdiv = 0x2, + .gpll_mdiv = 0x215, + .gpll_pdiv = 0xc, + .gpll_sdiv = 0x1, + .epll_mdiv = 0x60, + .epll_pdiv = 0x3, + .epll_sdiv = 0x3, + .vpll_mdiv = 0x96, + .vpll_pdiv = 0x3, + .vpll_sdiv = 0x2, + + .bpll_mdiv = 0x64, + .bpll_pdiv = 0x3, + .bpll_sdiv = 0x0, + .use_bpll = 0, + .pclk_cdrex_ratio = 0x5, + .direct_cmd_msr = { + 0x00020018, 0x00030000, 0x00010000, 0x00000d70 + }, + .timing_ref = 0x000000bb, + .timing_row = 0x8c36660f, + .timing_data = 0x3630580b, + .timing_power = 0x41000a44, + .phy0_dqs = 0x08080808, + .phy1_dqs = 0x08080808, + .phy0_dq = 0x08080808, + .phy1_dq = 0x08080808, + .phy0_tFS = 0x8, + .phy1_tFS = 0x8, + .phy0_pulld_dqs = 0xf, + .phy1_pulld_dqs = 0xf, + + .lpddr3_ctrl_phy_reset = 0x1, + .ctrl_start_point = 0x10, + .ctrl_inc = 0x10, + .ctrl_start = 0x1, + .ctrl_dll_on = 0x1, + .ctrl_ref = 0x8, + + .ctrl_force = 0x1a, + .ctrl_rdlat = 0x0b, + .ctrl_bstlen = 0x08, + + .fp_resync = 0x8, + .iv_size = 0x7, + .dfi_init_start = 1, + .aref_en = 1, + + .rd_fetch = 0x3, + + .zq_mode_dds = 0x5, + .zq_mode_term = 0x1, + .zq_mode_noterm = 1, + + /* + * Dynamic Clock: Always Running + * Memory Burst length: 8 + * Number of chips: 1 + * Memory Bus width: 32 bit + * Memory Type: DDR3 + * Additional Latancy for PLL: 0 Cycle + */ + .memcontrol = DMC_MEMCONTROL_CLK_STOP_DISABLE | + DMC_MEMCONTROL_DPWRDN_DISABLE | + DMC_MEMCONTROL_DPWRDN_ACTIVE_PRECHARGE | + DMC_MEMCONTROL_TP_DISABLE | + DMC_MEMCONTROL_DSREF_ENABLE | + DMC_MEMCONTROL_ADD_LAT_PALL_CYCLE(0) | + DMC_MEMCONTROL_MEM_TYPE_DDR3 | + DMC_MEMCONTROL_MEM_WIDTH_32BIT | + DMC_MEMCONTROL_NUM_CHIP_1 | + DMC_MEMCONTROL_BL_8 | + DMC_MEMCONTROL_PZQ_DISABLE | + DMC_MEMCONTROL_MRR_BYTE_7_0, + .memconfig = DMC_MEMCONFIGx_CHIP_MAP_INTERLEAVED | + DMC_MEMCONFIGx_CHIP_COL_10 | + DMC_MEMCONFIGx_CHIP_ROW_15 | + DMC_MEMCONFIGx_CHIP_BANK_8, + .membaseconfig0 = DMC_MEMBASECONFIG_VAL(0x40), + .membaseconfig1 = DMC_MEMBASECONFIG_VAL(0x80), + .prechconfig_tp_cnt = 0xff, + .dpwrdn_cyc = 0xff, + .dsref_cyc = 0xffff, + .concontrol = DMC_CONCONTROL_DFI_INIT_START_DISABLE | + DMC_CONCONTROL_TIMEOUT_LEVEL0 | + DMC_CONCONTROL_RD_FETCH_DISABLE | + DMC_CONCONTROL_EMPTY_DISABLE | + DMC_CONCONTROL_AREF_EN_DISABLE | + DMC_CONCONTROL_IO_PD_CON_DISABLE, + .dmc_channels = 2, + .chips_per_channel = 2, + .chips_to_configure = 1, + .send_zq_init = 1, + .impedance = IMP_OUTPUT_DRV_40_OHM, + .gate_leveling_enable = 1, + }, + { + .mem_manuf = MEM_MANUF_ELPIDA, + .mem_type = DDR_MODE_DDR3, + .frequency_mhz = 780, + .mpll_mdiv = 0x64, + .mpll_pdiv = 0x3, + .mpll_sdiv = 0x0, + .cpll_mdiv = 0xde, + .cpll_pdiv = 0x4, + .cpll_sdiv = 0x2, + .gpll_mdiv = 0x215, + .gpll_pdiv = 0xc, + .gpll_sdiv = 0x1, + .epll_mdiv = 0x60, + .epll_pdiv = 0x3, + .epll_sdiv = 0x3, + .vpll_mdiv = 0x96, + .vpll_pdiv = 0x3, + .vpll_sdiv = 0x2, + + .bpll_mdiv = 0x82, + .bpll_pdiv = 0x4, + .bpll_sdiv = 0x0, + .use_bpll = 1, + .pclk_cdrex_ratio = 0x5, + .direct_cmd_msr = { + 0x00020018, 0x00030000, 0x00010042, 0x00000d70 + }, + .timing_ref = 0x000000bb, + .timing_row = 0x8c36660f, + .timing_data = 0x3630580b, + .timing_power = 0x41000a44, + .phy0_dqs = 0x08080808, + .phy1_dqs = 0x08080808, + .phy0_dq = 0x08080808, + .phy1_dq = 0x08080808, + .phy0_tFS = 0x4, + .phy1_tFS = 0x4, + .phy0_pulld_dqs = 0xf, + .phy1_pulld_dqs = 0xf, + + .lpddr3_ctrl_phy_reset = 0x1, + .ctrl_start_point = 0x10, + .ctrl_inc = 0x10, + .ctrl_start = 0x1, + .ctrl_dll_on = 0x1, + .ctrl_ref = 0x8, + + .ctrl_force = 0x1a, + .ctrl_rdlat = 0x0b, + .ctrl_bstlen = 0x08, + + .fp_resync = 0x8, + .iv_size = 0x7, + .dfi_init_start = 1, + .aref_en = 1, + + .rd_fetch = 0x3, + + .zq_mode_dds = 0x7, + .zq_mode_term = 0x1, + .zq_mode_noterm = 0, + + /* + * Dynamic Clock: Always Running + * Memory Burst length: 8 + * Number of chips: 1 + * Memory Bus width: 32 bit + * Memory Type: DDR3 + * Additional Latancy for PLL: 0 Cycle + */ + .memcontrol = DMC_MEMCONTROL_CLK_STOP_DISABLE | + DMC_MEMCONTROL_DPWRDN_DISABLE | + DMC_MEMCONTROL_DPWRDN_ACTIVE_PRECHARGE | + DMC_MEMCONTROL_TP_DISABLE | + DMC_MEMCONTROL_DSREF_ENABLE | + DMC_MEMCONTROL_ADD_LAT_PALL_CYCLE(0) | + DMC_MEMCONTROL_MEM_TYPE_DDR3 | + DMC_MEMCONTROL_MEM_WIDTH_32BIT | + DMC_MEMCONTROL_NUM_CHIP_1 | + DMC_MEMCONTROL_BL_8 | + DMC_MEMCONTROL_PZQ_DISABLE | + DMC_MEMCONTROL_MRR_BYTE_7_0, + .memconfig = DMC_MEMCONFIGx_CHIP_MAP_INTERLEAVED | + DMC_MEMCONFIGx_CHIP_COL_10 | + DMC_MEMCONFIGx_CHIP_ROW_15 | + DMC_MEMCONFIGx_CHIP_BANK_8, + .membaseconfig0 = DMC_MEMBASECONFIG_VAL(0x40), + .membaseconfig1 = DMC_MEMBASECONFIG_VAL(0x80), + .prechconfig_tp_cnt = 0xff, + .dpwrdn_cyc = 0xff, + .dsref_cyc = 0xffff, + .concontrol = DMC_CONCONTROL_DFI_INIT_START_DISABLE | + DMC_CONCONTROL_TIMEOUT_LEVEL0 | + DMC_CONCONTROL_RD_FETCH_DISABLE | + DMC_CONCONTROL_EMPTY_DISABLE | + DMC_CONCONTROL_AREF_EN_DISABLE | + DMC_CONCONTROL_IO_PD_CON_DISABLE, + .dmc_channels = 2, + .chips_per_channel = 2, + .chips_to_configure = 1, + .send_zq_init = 1, + .impedance = IMP_OUTPUT_DRV_30_OHM, + .gate_leveling_enable = 0, + }, { + .mem_manuf = MEM_MANUF_SAMSUNG, + .mem_type = DDR_MODE_DDR3, + .frequency_mhz = 780, + .mpll_mdiv = 0x64, + .mpll_pdiv = 0x3, + .mpll_sdiv = 0x0, + .cpll_mdiv = 0xde, + .cpll_pdiv = 0x4, + .cpll_sdiv = 0x2, + .gpll_mdiv = 0x215, + .gpll_pdiv = 0xc, + .gpll_sdiv = 0x1, + .epll_mdiv = 0x60, + .epll_pdiv = 0x3, + .epll_sdiv = 0x3, + .vpll_mdiv = 0x96, + .vpll_pdiv = 0x3, + .vpll_sdiv = 0x2, + + .bpll_mdiv = 0x82, + .bpll_pdiv = 0x4, + .bpll_sdiv = 0x0, + .use_bpll = 1, + .pclk_cdrex_ratio = 0x5, + .direct_cmd_msr = { + 0x00020018, 0x00030000, 0x00010000, 0x00000d70 + }, + .timing_ref = 0x000000bb, + .timing_row = 0x8c36660f, + .timing_data = 0x3630580b, + .timing_power = 0x41000a44, + .phy0_dqs = 0x08080808, + .phy1_dqs = 0x08080808, + .phy0_dq = 0x08080808, + .phy1_dq = 0x08080808, + .phy0_tFS = 0x8, + .phy1_tFS = 0x8, + .phy0_pulld_dqs = 0xf, + .phy1_pulld_dqs = 0xf, + + .lpddr3_ctrl_phy_reset = 0x1, + .ctrl_start_point = 0x10, + .ctrl_inc = 0x10, + .ctrl_start = 0x1, + .ctrl_dll_on = 0x1, + .ctrl_ref = 0x8, + + .ctrl_force = 0x1a, + .ctrl_rdlat = 0x0b, + .ctrl_bstlen = 0x08, + + .fp_resync = 0x8, + .iv_size = 0x7, + .dfi_init_start = 1, + .aref_en = 1, + + .rd_fetch = 0x3, + + .zq_mode_dds = 0x5, + .zq_mode_term = 0x1, + .zq_mode_noterm = 1, + + /* + * Dynamic Clock: Always Running + * Memory Burst length: 8 + * Number of chips: 1 + * Memory Bus width: 32 bit + * Memory Type: DDR3 + * Additional Latancy for PLL: 0 Cycle + */ + .memcontrol = DMC_MEMCONTROL_CLK_STOP_DISABLE | + DMC_MEMCONTROL_DPWRDN_DISABLE | + DMC_MEMCONTROL_DPWRDN_ACTIVE_PRECHARGE | + DMC_MEMCONTROL_TP_DISABLE | + DMC_MEMCONTROL_DSREF_ENABLE | + DMC_MEMCONTROL_ADD_LAT_PALL_CYCLE(0) | + DMC_MEMCONTROL_MEM_TYPE_DDR3 | + DMC_MEMCONTROL_MEM_WIDTH_32BIT | + DMC_MEMCONTROL_NUM_CHIP_1 | + DMC_MEMCONTROL_BL_8 | + DMC_MEMCONTROL_PZQ_DISABLE | + DMC_MEMCONTROL_MRR_BYTE_7_0, + .memconfig = DMC_MEMCONFIGx_CHIP_MAP_INTERLEAVED | + DMC_MEMCONFIGx_CHIP_COL_10 | + DMC_MEMCONFIGx_CHIP_ROW_15 | + DMC_MEMCONFIGx_CHIP_BANK_8, + .membaseconfig0 = DMC_MEMBASECONFIG_VAL(0x40), + .membaseconfig1 = DMC_MEMBASECONFIG_VAL(0x80), + .prechconfig_tp_cnt = 0xff, + .dpwrdn_cyc = 0xff, + .dsref_cyc = 0xffff, + .concontrol = DMC_CONCONTROL_DFI_INIT_START_DISABLE | + DMC_CONCONTROL_TIMEOUT_LEVEL0 | + DMC_CONCONTROL_RD_FETCH_DISABLE | + DMC_CONCONTROL_EMPTY_DISABLE | + DMC_CONCONTROL_AREF_EN_DISABLE | + DMC_CONCONTROL_IO_PD_CON_DISABLE, + .dmc_channels = 2, + .chips_per_channel = 2, + .chips_to_configure = 1, + .send_zq_init = 1, + .impedance = IMP_OUTPUT_DRV_40_OHM, + .gate_leveling_enable = 1, + } +}; + +/** + * Detect what memory is present based on board strappings + * + * Boards have various resistor stuff options that are supposed to match + * which SDRAM is present (and which revision of the board this is). This + * uses the resistor stuff options to figure out what memory manufacturer + * to use for matching in the memory tables. + * + * @return A MEM_MANUF_XXX constant, or -1 if an error occurred. + */ +/* + * FIXME(dhendrix): This unwinds into a mess of board-specific code. The + * board's romstage.c file should detect the memory type and pass in + * appropriate parameters to whatever calls this. + */ +#define BOARD_REV_ELPIDA_MEMORY 3 +#define BOARD_REV_SAMSUNG_MEMORY 4 +static int autodetect_memory(void) +{ +// int board_rev = board_get_revision(); + int board_rev = BOARD_REV_ELPIDA_MEMORY; + + if (board_rev == -1) + return -1; + + switch (board_rev) { + case BOARD_REV_SAMSUNG_MEMORY: + return MEM_MANUF_SAMSUNG; + case BOARD_REV_ELPIDA_MEMORY: + return MEM_MANUF_ELPIDA; + } + + return -1; +} + +#ifdef CONFIG_SPL_BUILD + +/** + * Get the required memory type and speed (SPL version). + * + * In SPL we have no device tree, so we use the machine parameters + */ +int clock_get_mem_selection(enum ddr_mode *mem_type, + unsigned *frequency_mhz, unsigned *arm_freq, + enum mem_manuf *mem_manuf) +{ + struct spl_machine_param *params; + + params = spl_get_machine_params(); + *mem_type = params->mem_type; + *frequency_mhz = params->frequency_mhz; + *arm_freq = params->arm_freq_mhz; + if (params->mem_manuf == MEM_MANUF_AUTODETECT) { + *mem_manuf = autodetect_memory(); + if (*mem_manuf == -1) + return -1; + } else { + *mem_manuf = params->mem_manuf; + } + + return 0; +} + +#else + +static const char *mem_types[DDR_MODE_COUNT] = { + "DDR2", "DDR3", "LPDDR2", "LPDDR3" +}; + +static const char *mem_manufs[MEM_MANUF_COUNT] = { + "autodetect", "Elpida", "Samsung" +}; + +int clock_get_mem_selection(enum ddr_mode *mem_type, + unsigned *frequency_mhz, unsigned *arm_freq, + enum mem_manuf *mem_manuf) +{ + const char *typestr; + int node, i; + + node = fdtdec_next_compatible(gd->fdt_blob, 0, + COMPAT_SAMSUNG_EXYNOS_DMC); + if (node < 0) + die("No memory information available in device tree"); + typestr = fdt_getprop(gd->fdt_blob, node, "mem-type", NULL); + for (i = 0; i < DDR_MODE_COUNT; i++) { + if (!stricmp(typestr, mem_types[i])) + break; + } + if (i == DDR_MODE_COUNT) + die("Invalid memory type in device tree"); + *mem_type = i; + + typestr = fdt_getprop(gd->fdt_blob, node, "mem-manuf", NULL); + for (i = 0; i < MEM_MANUF_COUNT; i++) { + if (!stricmp(typestr, mem_manufs[i])) + break; + } + if (i == MEM_MANUF_COUNT) + die("Invalid memory manufacturer in device tree"); + + if (i == MEM_MANUF_AUTODETECT) { + *mem_manuf = autodetect_memory(); + if (*mem_manuf == -1) + return -1; + } else { + *mem_manuf = i; + } + + *frequency_mhz = fdtdec_get_int(gd->fdt_blob, node, "clock-frequency", + 0); + if (!*frequency_mhz) + die("Invalid memory frequency in device tree"); + + *arm_freq = fdtdec_get_int(gd->fdt_blob, node, "arm-frequency", 0); + /* TODO: Remove all these panics/dies, and just return an error code */ + if (!*arm_freq) + die("Invalid ARM frequency in device tree"); + + return 0; +} + +const char *clock_get_mem_type_name(enum ddr_mode mem_type) +{ + if (mem_type >= 0 && mem_type < DDR_MODE_COUNT) + return mem_types[mem_type]; + + return "<unknown>"; +} + +const char *clock_get_mem_manuf_name(enum mem_manuf mem_manuf) +{ + if (mem_manuf >= 0 && mem_manuf < MEM_MANUF_COUNT) + return mem_manufs[mem_manuf]; + + return "<unknown>"; +} +#endif + +/* Get the ratios for setting ARM clock */ +struct arm_clk_ratios *get_arm_ratios(void); /* FIXME: silence compiler... */ +struct arm_clk_ratios *get_arm_ratios(void) +{ + struct arm_clk_ratios *arm_ratio; + enum ddr_mode mem_type; + enum mem_manuf mem_manuf; + unsigned frequency_mhz, arm_freq; + int i; + + /* TODO(sjg@chromium.org): Return NULL and have caller deal with it */ + if (clock_get_mem_selection(&mem_type, &frequency_mhz, + &arm_freq, &mem_manuf)) + ; + for (i = 0, arm_ratio = arm_clk_ratios; i < ARRAY_SIZE(arm_clk_ratios); + i++, arm_ratio++) { + if (arm_ratio->arm_freq_mhz == arm_freq) + return arm_ratio; + } + + die("get_arm_ratios: Failed to find ratio\n"); + return NULL; +} + +struct mem_timings *clock_get_mem_timings(void) +{ + struct mem_timings *mem; + enum ddr_mode mem_type; + enum mem_manuf mem_manuf; + unsigned frequency_mhz, arm_freq; + int i; + + if (!clock_get_mem_selection(&mem_type, &frequency_mhz, + &arm_freq, &mem_manuf)) { + for (i = 0, mem = mem_timings; i < ARRAY_SIZE(mem_timings); + i++, mem++) { + if (mem->mem_type == mem_type && + mem->frequency_mhz == frequency_mhz && + mem->mem_manuf == mem_manuf) + return mem; + } + } + /* TODO: Call panic() here */ + while (1) + ; + return NULL; +} + +void system_clock_init() +{ + struct exynos5_clock *clk = (struct exynos5_clock *)EXYNOS5_CLOCK_BASE; + struct exynos5_mct_regs *mct_regs = + (struct exynos5_mct_regs *)EXYNOS5_MULTI_CORE_TIMER_BASE; + struct mem_timings *mem; + struct arm_clk_ratios *arm_clk_ratio; + u32 val, tmp; + + /* Turn on the MCT as early as possible. */ + mct_regs->g_tcon |= (1 << 8); + + mem = clock_get_mem_timings(); + arm_clk_ratio = get_arm_ratios(); + + clrbits_le32(&clk->src_cpu, MUX_APLL_SEL_MASK); + do { + val = readl(&clk->mux_stat_cpu); + } while ((val | MUX_APLL_SEL_MASK) != val); + + clrbits_le32(&clk->src_core1, MUX_MPLL_SEL_MASK); + do { + val = readl(&clk->mux_stat_core1); + } while ((val | MUX_MPLL_SEL_MASK) != val); + + clrbits_le32(&clk->src_top2, MUX_CPLL_SEL_MASK); + clrbits_le32(&clk->src_top2, MUX_EPLL_SEL_MASK); + clrbits_le32(&clk->src_top2, MUX_VPLL_SEL_MASK); + clrbits_le32(&clk->src_top2, MUX_GPLL_SEL_MASK); + tmp = MUX_CPLL_SEL_MASK | MUX_EPLL_SEL_MASK | MUX_VPLL_SEL_MASK + | MUX_GPLL_SEL_MASK; + do { + val = readl(&clk->mux_stat_top2); + } while ((val | tmp) != val); + + clrbits_le32(&clk->src_cdrex, MUX_BPLL_SEL_MASK); + do { + val = readl(&clk->mux_stat_cdrex); + } while ((val | MUX_BPLL_SEL_MASK) != val); + + /* PLL locktime */ + writel(APLL_LOCK_VAL, &clk->apll_lock); + + writel(MPLL_LOCK_VAL, &clk->mpll_lock); + + writel(BPLL_LOCK_VAL, &clk->bpll_lock); + + writel(CPLL_LOCK_VAL, &clk->cpll_lock); + + writel(GPLL_LOCK_VAL, &clk->gpll_lock); + + writel(EPLL_LOCK_VAL, &clk->epll_lock); + + writel(VPLL_LOCK_VAL, &clk->vpll_lock); + + writel(CLK_REG_DISABLE, &clk->pll_div2_sel); + + writel(MUX_HPM_SEL_MASK, &clk->src_cpu); + do { + val = readl(&clk->mux_stat_cpu); + } while ((val | HPM_SEL_SCLK_MPLL) != val); + + val = arm_clk_ratio->arm2_ratio << 28 + | arm_clk_ratio->apll_ratio << 24 + | arm_clk_ratio->pclk_dbg_ratio << 20 + | arm_clk_ratio->atb_ratio << 16 + | arm_clk_ratio->periph_ratio << 12 + | arm_clk_ratio->acp_ratio << 8 + | arm_clk_ratio->cpud_ratio << 4 + | arm_clk_ratio->arm_ratio; + writel(val, &clk->div_cpu0); + do { + val = readl(&clk->div_stat_cpu0); + } while (0 != val); + + writel(CLK_DIV_CPU1_VAL, &clk->div_cpu1); + do { + val = readl(&clk->div_stat_cpu1); + } while (0 != val); + + /* Set APLL */ + writel(APLL_CON1_VAL, &clk->apll_con1); + val = set_pll(arm_clk_ratio->apll_mdiv, arm_clk_ratio->apll_pdiv, + arm_clk_ratio->apll_sdiv); + writel(val, &clk->apll_con0); + while ((readl(&clk->apll_con0) & APLL_CON0_LOCKED) == 0) + ; + + /* Set MPLL */ + writel(MPLL_CON1_VAL, &clk->mpll_con1); + val = set_pll(mem->mpll_mdiv, mem->mpll_pdiv, mem->mpll_sdiv); + writel(val, &clk->mpll_con0); + while ((readl(&clk->mpll_con0) & MPLL_CON0_LOCKED) == 0) + ; + + /* + * Configure MUX_MPLL_FOUT to choose the direct clock source + * path and avoid the fixed DIV/2 block to save power + */ + setbits_le32(&clk->pll_div2_sel, MUX_MPLL_FOUT_SEL); + + /* Set BPLL */ + if (mem->use_bpll) { + writel(BPLL_CON1_VAL, &clk->bpll_con1); + val = set_pll(mem->bpll_mdiv, mem->bpll_pdiv, mem->bpll_sdiv); + writel(val, &clk->bpll_con0); + while ((readl(&clk->bpll_con0) & BPLL_CON0_LOCKED) == 0) + ; + + setbits_le32(&clk->pll_div2_sel, MUX_BPLL_FOUT_SEL); + } + + /* Set CPLL */ + writel(CPLL_CON1_VAL, &clk->cpll_con1); + val = set_pll(mem->cpll_mdiv, mem->cpll_pdiv, mem->cpll_sdiv); + writel(val, &clk->cpll_con0); + while ((readl(&clk->cpll_con0) & CPLL_CON0_LOCKED) == 0) + ; + + /* Set GPLL */ + writel(GPLL_CON1_VAL, &clk->gpll_con1); + val = set_pll(mem->gpll_mdiv, mem->gpll_pdiv, mem->gpll_sdiv); + writel(val, &clk->gpll_con0); + while ((readl(&clk->gpll_con0) & GPLL_CON0_LOCKED) == 0) + ; + + /* Set EPLL */ + writel(EPLL_CON2_VAL, &clk->epll_con2); + writel(EPLL_CON1_VAL, &clk->epll_con1); + val = set_pll(mem->epll_mdiv, mem->epll_pdiv, mem->epll_sdiv); + writel(val, &clk->epll_con0); + while ((readl(&clk->epll_con0) & EPLL_CON0_LOCKED) == 0) + ; + + /* Set VPLL */ + writel(VPLL_CON2_VAL, &clk->vpll_con2); + writel(VPLL_CON1_VAL, &clk->vpll_con1); + val = set_pll(mem->vpll_mdiv, mem->vpll_pdiv, mem->vpll_sdiv); + writel(val, &clk->vpll_con0); + while ((readl(&clk->vpll_con0) & VPLL_CON0_LOCKED) == 0) + ; + + writel(CLK_SRC_CORE0_VAL, &clk->src_core0); + writel(CLK_DIV_CORE0_VAL, &clk->div_core0); + while (readl(&clk->div_stat_core0) != 0) + ; + + writel(CLK_DIV_CORE1_VAL, &clk->div_core1); + while (readl(&clk->div_stat_core1) != 0) + ; + + writel(CLK_DIV_SYSRGT_VAL, &clk->div_sysrgt); + while (readl(&clk->div_stat_sysrgt) != 0) + ; + + writel(CLK_DIV_ACP_VAL, &clk->div_acp); + while (readl(&clk->div_stat_acp) != 0) + ; + + writel(CLK_DIV_SYSLFT_VAL, &clk->div_syslft); + while (readl(&clk->div_stat_syslft) != 0) + ; + + writel(CLK_SRC_TOP0_VAL, &clk->src_top0); + writel(CLK_SRC_TOP1_VAL, &clk->src_top1); + writel(TOP2_VAL, &clk->src_top2); + writel(CLK_SRC_TOP3_VAL, &clk->src_top3); + + writel(CLK_DIV_TOP0_VAL, &clk->div_top0); + while (readl(&clk->div_stat_top0)) + ; + + writel(CLK_DIV_TOP1_VAL, &clk->div_top1); + while (readl(&clk->div_stat_top1)) + ; + + writel(CLK_SRC_LEX_VAL, &clk->src_lex); + while (1) { + val = readl(&clk->mux_stat_lex); + if (val == (val | 1)) + break; + } + + writel(CLK_DIV_LEX_VAL, &clk->div_lex); + while (readl(&clk->div_stat_lex)) + ; + + writel(CLK_DIV_R0X_VAL, &clk->div_r0x); + while (readl(&clk->div_stat_r0x)) + ; + + writel(CLK_DIV_R0X_VAL, &clk->div_r0x); + while (readl(&clk->div_stat_r0x)) + ; + + writel(CLK_DIV_R1X_VAL, &clk->div_r1x); + while (readl(&clk->div_stat_r1x)) + ; + + if (mem->use_bpll) { + writel(MUX_BPLL_SEL_MASK | MUX_MCLK_CDREX_SEL | + MUX_MCLK_DPHY_SEL, &clk->src_cdrex); + } else { + writel(CLK_REG_DISABLE, &clk->src_cdrex); + } + + writel(CLK_DIV_CDREX_VAL, &clk->div_cdrex); + while (readl(&clk->div_stat_cdrex)) + ; + + val = readl(&clk->src_cpu); + val |= CLK_SRC_CPU_VAL; + writel(val, &clk->src_cpu); + + val = readl(&clk->src_top2); + val |= CLK_SRC_TOP2_VAL; + writel(val, &clk->src_top2); + + val = readl(&clk->src_core1); + val |= CLK_SRC_CORE1_VAL; + writel(val, &clk->src_core1); + + writel(CLK_SRC_FSYS0_VAL, &clk->src_fsys); + writel(CLK_DIV_FSYS0_VAL, &clk->div_fsys0); + while (readl(&clk->div_stat_fsys0)) + ; + + writel(CLK_REG_DISABLE, &clk->clkout_cmu_cpu); + writel(CLK_REG_DISABLE, &clk->clkout_cmu_core); + writel(CLK_REG_DISABLE, &clk->clkout_cmu_acp); + writel(CLK_REG_DISABLE, &clk->clkout_cmu_top); + writel(CLK_REG_DISABLE, &clk->clkout_cmu_lex); + writel(CLK_REG_DISABLE, &clk->clkout_cmu_r0x); + writel(CLK_REG_DISABLE, &clk->clkout_cmu_r1x); + writel(CLK_REG_DISABLE, &clk->clkout_cmu_cdrex); + + writel(CLK_SRC_PERIC0_VAL, &clk->src_peric0); + writel(CLK_DIV_PERIC0_VAL, &clk->div_peric0); + + writel(CLK_SRC_PERIC1_VAL, &clk->src_peric1); + writel(CLK_DIV_PERIC1_VAL, &clk->div_peric1); + writel(CLK_DIV_PERIC2_VAL, &clk->div_peric2); + writel(SCLK_SRC_ISP_VAL, &clk->sclk_src_isp); + writel(SCLK_DIV_ISP_VAL, &clk->sclk_div_isp); + writel(CLK_DIV_ISP0_VAL, &clk->div_isp0); + writel(CLK_DIV_ISP1_VAL, &clk->div_isp1); + writel(CLK_DIV_ISP2_VAL, &clk->div_isp2); + + /* FIMD1 SRC CLK SELECTION */ + writel(CLK_SRC_DISP1_0_VAL, &clk->src_disp1_0); + + val = MMC2_PRE_RATIO_VAL << MMC2_PRE_RATIO_OFFSET + | MMC2_RATIO_VAL << MMC2_RATIO_OFFSET + | MMC3_PRE_RATIO_VAL << MMC3_PRE_RATIO_OFFSET + | MMC3_RATIO_VAL << MMC3_RATIO_OFFSET; + writel(val, &clk->div_fsys2); +} + +void clock_gate(void) +{ + struct exynos5_clock *clk = (struct exynos5_clock *)EXYNOS5_CLOCK_BASE; + + /* CLK_GATE_IP_SYSRGT */ + clrbits_le32(&clk->gate_ip_sysrgt, CLK_C2C_MASK); + + /* CLK_GATE_IP_ACP */ + clrbits_le32(&clk->gate_ip_acp, CLK_SMMUG2D_MASK | + CLK_SMMUSSS_MASK | + CLK_SMMUMDMA_MASK | + CLK_ID_REMAPPER_MASK | + CLK_G2D_MASK | + CLK_SSS_MASK | + CLK_MDMA_MASK | + CLK_SECJTAG_MASK); + + /* CLK_GATE_BUS_SYSLFT */ + clrbits_le32(&clk->gate_bus_syslft, CLK_EFCLK_MASK); + + /* CLK_GATE_IP_ISP0 */ + clrbits_le32(&clk->gate_ip_isp0, CLK_UART_ISP_MASK | + CLK_WDT_ISP_MASK | + CLK_PWM_ISP_MASK | + CLK_MTCADC_ISP_MASK | + CLK_I2C1_ISP_MASK | + CLK_I2C0_ISP_MASK | + CLK_MPWM_ISP_MASK | + CLK_MCUCTL_ISP_MASK | + CLK_INT_COMB_ISP_MASK | + CLK_SMMU_MCUISP_MASK | + CLK_SMMU_SCALERP_MASK | + CLK_SMMU_SCALERC_MASK | + CLK_SMMU_FD_MASK | + CLK_SMMU_DRC_MASK | + CLK_SMMU_ISP_MASK | + CLK_GICISP_MASK | + CLK_ARM9S_MASK | + CLK_MCUISP_MASK | + CLK_SCALERP_MASK | + CLK_SCALERC_MASK | + CLK_FD_MASK | + CLK_DRC_MASK | + CLK_ISP_MASK); + + /* CLK_GATE_IP_ISP1 */ + clrbits_le32(&clk->gate_ip_isp1, CLK_SPI1_ISP_MASK | + CLK_SPI0_ISP_MASK | + CLK_SMMU3DNR_MASK | + CLK_SMMUDIS1_MASK | + CLK_SMMUDIS0_MASK | + CLK_SMMUODC_MASK | + CLK_3DNR_MASK | + CLK_DIS_MASK | + CLK_ODC_MASK); + + /* CLK_GATE_SCLK_ISP */ + clrbits_le32(&clk->gate_sclk_isp, SCLK_MPWM_ISP_MASK); + + /* CLK_GATE_IP_GSCL */ + clrbits_le32(&clk->gate_ip_gscl, CLK_SMMUFIMC_LITE2_MASK | + CLK_SMMUFIMC_LITE1_MASK | + CLK_SMMUFIMC_LITE0_MASK | + CLK_SMMUGSCL3_MASK | + CLK_SMMUGSCL2_MASK | + CLK_SMMUGSCL1_MASK | + CLK_SMMUGSCL0_MASK | + CLK_GSCL_WRAP_B_MASK | + CLK_GSCL_WRAP_A_MASK | + CLK_CAMIF_TOP_MASK | + CLK_GSCL3_MASK | + CLK_GSCL2_MASK | + CLK_GSCL1_MASK | + CLK_GSCL0_MASK); + + /* CLK_GATE_IP_DISP1 */ + clrbits_le32(&clk->gate_ip_disp1, CLK_SMMUTVX_MASK | + CLK_ASYNCTVX_MASK | + CLK_HDMI_MASK | + CLK_MIXER_MASK | + CLK_DSIM1_MASK); + + /* CLK_GATE_IP_MFC */ + clrbits_le32(&clk->gate_ip_mfc, CLK_SMMUMFCR_MASK | + CLK_SMMUMFCL_MASK | + CLK_MFC_MASK); + + /* CLK_GATE_IP_GEN */ + clrbits_le32(&clk->gate_ip_gen, CLK_SMMUMDMA1_MASK | + CLK_SMMUJPEG_MASK | + CLK_SMMUROTATOR_MASK | + CLK_MDMA1_MASK | + CLK_JPEG_MASK | + CLK_ROTATOR_MASK); + + /* CLK_GATE_IP_FSYS */ + clrbits_le32(&clk->gate_ip_fsys, CLK_WDT_IOP_MASK | + CLK_SMMUMCU_IOP_MASK | + CLK_SATA_PHY_I2C_MASK | + CLK_SATA_PHY_CTRL_MASK | + CLK_MCUCTL_MASK | + CLK_NFCON_MASK | + CLK_SMMURTIC_MASK | + CLK_RTIC_MASK | + CLK_MIPI_HSI_MASK | + CLK_USBOTG_MASK | + CLK_SATA_MASK | + CLK_PDMA1_MASK | + CLK_PDMA0_MASK | + CLK_MCU_IOP_MASK); + + /* CLK_GATE_IP_PERIC */ + clrbits_le32(&clk->gate_ip_peric, CLK_HS_I2C3_MASK | + CLK_HS_I2C2_MASK | + CLK_HS_I2C1_MASK | + CLK_HS_I2C0_MASK | + CLK_AC97_MASK | + CLK_SPDIF_MASK | + CLK_PCM2_MASK | + CLK_PCM1_MASK | + CLK_I2S2_MASK | + CLK_SPI2_MASK | + CLK_SPI0_MASK); + + /* CLK_GATE_IP_PERIS */ + clrbits_le32(&clk->gate_ip_peris, CLK_RTC_MASK | + CLK_TZPC9_MASK | + CLK_TZPC8_MASK | + CLK_TZPC7_MASK | + CLK_TZPC6_MASK | + CLK_TZPC5_MASK | + CLK_TZPC4_MASK | + CLK_TZPC3_MASK | + CLK_TZPC2_MASK | + CLK_TZPC1_MASK | + CLK_TZPC0_MASK | + CLK_CHIPID_MASK); + + /* CLK_GATE_BLOCK */ + clrbits_le32(&clk->gate_block, CLK_ACP_MASK); + + /* CLK_GATE_IP_CDREX */ + clrbits_le32(&clk->gate_ip_cdrex, CLK_DPHY0_MASK | + CLK_DPHY1_MASK | + CLK_TZASC_DRBXR_MASK); + +} + +void clock_init_dp_clock(void) +{ + struct exynos5_clock *clk = (struct exynos5_clock *)EXYNOS5_CLOCK_BASE; + + /* DP clock enable */ + setbits_le32(&clk->gate_ip_disp1, CLK_GATE_DP1_ALLOW); + + /* We run DP at 267 Mhz */ + setbits_le32(&clk->div_disp1_0, CLK_DIV_DISP1_0_FIMD1); +} + +#ifdef CONFIG_SPL_BUILD +/* + * This is a custom implementation for the udelay(), as we do not the timer + * initialise during the SPL boot. We are assuming the cpu takes 3 instruction + * pre cycle. This is based on the implementation of sdelay() function. + */ +void udelay(unsigned usec) +{ + unsigned long count; + + /* TODO(alim.akhtar@samsung.com): Comment on why divided by 30000000 */ + count = usec * (get_pll_clk(APLL) / (3 * 10000000)); + sdelay(count); +} +#endif diff --git a/src/cpu/samsung/exynos5250/dmc_common.c b/src/cpu/samsung/exynos5250/dmc_common.c new file mode 100644 index 0000000..e66043a --- /dev/null +++ b/src/cpu/samsung/exynos5250/dmc_common.c @@ -0,0 +1,200 @@ +/* + * Mem setup common file for different types of DDR present on SMDK5250 boards. + * + * Copyright (C) 2012 Samsung Electronics + * + * 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 <assert.h> +#include <common.h> +#include <console/console.h> +#include <cpu/samsung/exynos5250/setup.h> +#include <cpu/samsung/exynos-common/spl.h> +#include <system.h> + +#include "clock_init.h" +#include "setup.h" + +#define ZQ_INIT_TIMEOUT 10000 + +int dmc_config_zq(struct mem_timings *mem, + struct exynos5_phy_control *phy0_ctrl, + struct exynos5_phy_control *phy1_ctrl) +{ + unsigned long val = 0; + int i; + + /* + * ZQ Calibration: + * Select Driver Strength, + * long calibration for manual calibration + */ + val = PHY_CON16_RESET_VAL; + val |= mem->zq_mode_dds << PHY_CON16_ZQ_MODE_DDS_SHIFT; + val |= mem->zq_mode_term << PHY_CON16_ZQ_MODE_TERM_SHIFT; + val |= ZQ_CLK_DIV_EN; + writel(val, &phy0_ctrl->phy_con16); + writel(val, &phy1_ctrl->phy_con16); + + /* Disable termination */ + if (mem->zq_mode_noterm) + val |= PHY_CON16_ZQ_MODE_NOTERM_MASK; + writel(val, &phy0_ctrl->phy_con16); + writel(val, &phy1_ctrl->phy_con16); + + /* ZQ_MANUAL_START: Enable */ + val |= ZQ_MANUAL_STR; + writel(val, &phy0_ctrl->phy_con16); + writel(val, &phy1_ctrl->phy_con16); + + /* ZQ_MANUAL_START: Disable */ + val &= ~ZQ_MANUAL_STR; + + /* + * Since we are manaully calibrating the ZQ values, + * we are looping for the ZQ_init to complete. + */ + i = ZQ_INIT_TIMEOUT; + while ((readl(&phy0_ctrl->phy_con17) & ZQ_DONE) != ZQ_DONE && i > 0) { + sdelay(100); + i--; + } + if (!i) + return -1; + writel(val, &phy0_ctrl->phy_con16); + + i = ZQ_INIT_TIMEOUT; + while ((readl(&phy1_ctrl->phy_con17) & ZQ_DONE) != ZQ_DONE && i > 0) { + sdelay(100); + i--; + } + if (!i) + return -1; + writel(val, &phy1_ctrl->phy_con16); + + return 0; +} + +void update_reset_dll(struct exynos5_dmc *dmc, enum ddr_mode mode) +{ + unsigned long val; + + if (mode == DDR_MODE_DDR3) { + val = MEM_TERM_EN | PHY_TERM_EN | DMC_CTRL_SHGATE; + writel(val, &dmc->phycontrol0); + } + + /* Update DLL Information: Force DLL Resyncronization */ + val = readl(&dmc->phycontrol0); + val |= FP_RSYNC; + writel(val, &dmc->phycontrol0); + + /* Reset Force DLL Resyncronization */ + val = readl(&dmc->phycontrol0); + val &= ~FP_RSYNC; + writel(val, &dmc->phycontrol0); +} + +void dmc_config_mrs(struct mem_timings *mem, struct exynos5_dmc *dmc) +{ + int channel, chip; + + for (channel = 0; channel < mem->dmc_channels; channel++) { + unsigned long mask; + + mask = channel << DIRECT_CMD_CHANNEL_SHIFT; + for (chip = 0; chip < mem->chips_to_configure; chip++) { + int i; + + mask |= chip << DIRECT_CMD_CHIP_SHIFT; + + /* Sending NOP command */ + writel(DIRECT_CMD_NOP | mask, &dmc->directcmd); + + /* + * TODO(alim.akhtar@samsung.com): Do we need these + * delays? This one and the next were not there for + * DDR3. + */ + sdelay(0x10000); + + /* Sending EMRS/MRS commands */ + for (i = 0; i < MEM_TIMINGS_MSR_COUNT; i++) { + writel(mem->direct_cmd_msr[i] | mask, + &dmc->directcmd); + sdelay(0x10000); + } + + if (mem->send_zq_init) { + /* Sending ZQINIT command */ + writel(DIRECT_CMD_ZQINIT | mask, + &dmc->directcmd); + + sdelay(10000); + } + } + } +} + +void dmc_config_prech(struct mem_timings *mem, struct exynos5_dmc *dmc) +{ + int channel, chip; + + for (channel = 0; channel < mem->dmc_channels; channel++) { + unsigned long mask; + + mask = channel << DIRECT_CMD_CHANNEL_SHIFT; + for (chip = 0; chip < mem->chips_per_channel; chip++) { + mask |= chip << DIRECT_CMD_CHIP_SHIFT; + + /* PALL (all banks precharge) CMD */ + writel(DIRECT_CMD_PALL | mask, &dmc->directcmd); + sdelay(0x10000); + } + } +} + +void dmc_config_memory(struct mem_timings *mem, struct exynos5_dmc *dmc) +{ + writel(mem->memconfig, &dmc->memconfig0); + writel(mem->memconfig, &dmc->memconfig1); + writel(DMC_MEMBASECONFIG0_VAL, &dmc->membaseconfig0); + writel(DMC_MEMBASECONFIG1_VAL, &dmc->membaseconfig1); +} + +void mem_ctrl_init() +{ + struct spl_machine_param *param = spl_get_machine_params(); + struct mem_timings *mem; + int ret; + + mem = clock_get_mem_timings(); + + /* If there are any other memory variant, add their init call below */ + if (param->mem_type == DDR_MODE_DDR3) { + ret = ddr3_mem_ctrl_init(mem, param->mem_iv_size); + if (ret) { + printk(BIOS_ERR, "Memory controller init failed, err: %u", ret); + BUG(); + } + } else { + die("Unknown memory type"); + } +} diff --git a/src/cpu/samsung/exynos5250/dmc_init_ddr3.c b/src/cpu/samsung/exynos5250/dmc_init_ddr3.c new file mode 100644 index 0000000..6ef10bf --- /dev/null +++ b/src/cpu/samsung/exynos5250/dmc_init_ddr3.c @@ -0,0 +1,249 @@ +/* + * DDR3 mem setup file for SMDK5250 board based on EXYNOS5 + * + * Copyright (C) 2012 Samsung Electronics + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +#include <config.h> +#include <arch/io.h> +//#include "clock.h" +/* FIXME(dhendrix): untangle clock/clk ... */ +#include <cpu/samsung/s5p-common/clock.h> +#include <system.h> +#include "clk.h" +#include "cpu.h" +#include "dmc.h" +#include "setup.h" +#include "clock_init.h" + +#define RDLVL_COMPLETE_TIMEOUT 10000 + +static void reset_phy_ctrl(void) +{ + struct exynos5_clock *clk = (struct exynos5_clock *)EXYNOS5_CLOCK_BASE; + + writel(LPDDR3PHY_CTRL_PHY_RESET_OFF, &clk->lpddr3phy_ctrl); + writel(LPDDR3PHY_CTRL_PHY_RESET, &clk->lpddr3phy_ctrl); + + /* + * For proper memory initialization there should be a minimum delay of + * 500us after the LPDDR3PHY_CTRL_PHY_RESET signal. + * The below value is an approximate value whose calculation in done + * considering that sdelay takes 2 instruction for every 1 delay cycle. + * And assuming each instruction takes 1 clock cycle i.e 1/(1.7 Ghz)sec + * So for 500 usec, the number of delay cycle should be + * (500 * 10^-6) * (1.7 * 10^9) / 2 = 425000 + * + * TODO(hatim.rv@samsung.com): Implement the delay using timer/counter + */ + sdelay(425000); +} + +int ddr3_mem_ctrl_init(struct mem_timings *mem, unsigned long mem_iv_size) +{ + unsigned int val; + struct exynos5_phy_control *phy0_ctrl, *phy1_ctrl; + struct exynos5_dmc *dmc; + int i; + + phy0_ctrl = (struct exynos5_phy_control *)EXYNOS5_DMC_PHY0_BASE; + phy1_ctrl = (struct exynos5_phy_control *)EXYNOS5_DMC_PHY1_BASE; + dmc = (struct exynos5_dmc *)EXYNOS5_DMC_CTRL_BASE; + + reset_phy_ctrl(); + + /* Set Impedance Output Driver */ + val = (mem->impedance << CA_CK_DRVR_DS_OFFSET) | + (mem->impedance << CA_CKE_DRVR_DS_OFFSET) | + (mem->impedance << CA_CS_DRVR_DS_OFFSET) | + (mem->impedance << CA_ADR_DRVR_DS_OFFSET); + writel(val, &phy0_ctrl->phy_con39); + writel(val, &phy1_ctrl->phy_con39); + + /* Set Read Latency and Burst Length for PHY0 and PHY1 */ + val = (mem->ctrl_bstlen << PHY_CON42_CTRL_BSTLEN_SHIFT) | + (mem->ctrl_rdlat << PHY_CON42_CTRL_RDLAT_SHIFT); + writel(val, &phy0_ctrl->phy_con42); + writel(val, &phy1_ctrl->phy_con42); + + /* ZQ Calibration */ + if (dmc_config_zq(mem, phy0_ctrl, phy1_ctrl)) + return SETUP_ERR_ZQ_CALIBRATION_FAILURE; + + /* DQ Signal */ + writel(mem->phy0_pulld_dqs, &phy0_ctrl->phy_con14); + writel(mem->phy1_pulld_dqs, &phy1_ctrl->phy_con14); + + writel(mem->concontrol | (mem->rd_fetch << CONCONTROL_RD_FETCH_SHIFT) + | (mem->dfi_init_start << CONCONTROL_DFI_INIT_START_SHIFT), + &dmc->concontrol); + + update_reset_dll(dmc, DDR_MODE_DDR3); + + /* DQS Signal */ + writel(mem->phy0_dqs, &phy0_ctrl->phy_con4); + writel(mem->phy1_dqs, &phy1_ctrl->phy_con4); + + writel(mem->phy0_dq, &phy0_ctrl->phy_con6); + writel(mem->phy1_dq, &phy1_ctrl->phy_con6); + + writel(mem->phy0_tFS, &phy0_ctrl->phy_con10); + writel(mem->phy1_tFS, &phy1_ctrl->phy_con10); + + val = (mem->ctrl_start_point << PHY_CON12_CTRL_START_POINT_SHIFT) | + (mem->ctrl_inc << PHY_CON12_CTRL_INC_SHIFT) | + (mem->ctrl_dll_on << PHY_CON12_CTRL_DLL_ON_SHIFT) | + (mem->ctrl_ref << PHY_CON12_CTRL_REF_SHIFT); + writel(val, &phy0_ctrl->phy_con12); + writel(val, &phy1_ctrl->phy_con12); + + /* Start DLL locking */ + writel(val | (mem->ctrl_start << PHY_CON12_CTRL_START_SHIFT), + &phy0_ctrl->phy_con12); + writel(val | (mem->ctrl_start << PHY_CON12_CTRL_START_SHIFT), + &phy1_ctrl->phy_con12); + + update_reset_dll(dmc, DDR_MODE_DDR3); + + writel(mem->concontrol | (mem->rd_fetch << CONCONTROL_RD_FETCH_SHIFT), + &dmc->concontrol); + + /* Memory Channel Inteleaving Size */ + writel(mem->iv_size, &dmc->ivcontrol); + + /* Set DMC MEMCONTROL register */ + val = mem->memcontrol & ~DMC_MEMCONTROL_DSREF_ENABLE; + writel(val, &dmc->memcontrol); + + writel(mem->memconfig, &dmc->memconfig0); + writel(mem->memconfig, &dmc->memconfig1); + writel(mem->membaseconfig0, &dmc->membaseconfig0); + writel(mem->membaseconfig1, &dmc->membaseconfig1); + + /* Precharge Configuration */ + writel(mem->prechconfig_tp_cnt << PRECHCONFIG_TP_CNT_SHIFT, + &dmc->prechconfig); + + /* Power Down mode Configuration */ + writel(mem->dpwrdn_cyc << PWRDNCONFIG_DPWRDN_CYC_SHIFT | + mem->dsref_cyc << PWRDNCONFIG_DSREF_CYC_SHIFT, + &dmc->pwrdnconfig); + + /* TimingRow, TimingData, TimingPower and Timingaref + * values as per Memory AC parameters + */ + writel(mem->timing_ref, &dmc->timingref); + writel(mem->timing_row, &dmc->timingrow); + writel(mem->timing_data, &dmc->timingdata); + writel(mem->timing_power, &dmc->timingpower); + + /* Send PALL command */ + dmc_config_prech(mem, dmc); + + /* Send NOP, MRS and ZQINIT commands */ + dmc_config_mrs(mem, dmc); + + if (mem->gate_leveling_enable) { + val = PHY_CON0_RESET_VAL; + val |= P0_CMD_EN; + writel(val, &phy0_ctrl->phy_con0); + writel(val, &phy1_ctrl->phy_con0); + + val = PHY_CON2_RESET_VAL; + val |= INIT_DESKEW_EN; + writel(val, &phy0_ctrl->phy_con2); + writel(val, &phy1_ctrl->phy_con2); + + val = PHY_CON0_RESET_VAL; + val |= P0_CMD_EN; + val |= BYTE_RDLVL_EN; + writel(val, &phy0_ctrl->phy_con0); + writel(val, &phy1_ctrl->phy_con0); + + val = (mem->ctrl_start_point << + PHY_CON12_CTRL_START_POINT_SHIFT) | + (mem->ctrl_inc << PHY_CON12_CTRL_INC_SHIFT) | + (mem->ctrl_force << PHY_CON12_CTRL_FORCE_SHIFT) | + (mem->ctrl_start << PHY_CON12_CTRL_START_SHIFT) | + (mem->ctrl_ref << PHY_CON12_CTRL_REF_SHIFT); + writel(val, &phy0_ctrl->phy_con12); + writel(val, &phy1_ctrl->phy_con12); + + val = PHY_CON2_RESET_VAL; + val |= INIT_DESKEW_EN; + val |= RDLVL_GATE_EN; + writel(val, &phy0_ctrl->phy_con2); + writel(val, &phy1_ctrl->phy_con2); + + val = PHY_CON0_RESET_VAL; + val |= P0_CMD_EN; + val |= BYTE_RDLVL_EN; + val |= CTRL_SHGATE; + writel(val, &phy0_ctrl->phy_con0); + writel(val, &phy1_ctrl->phy_con0); + + val = PHY_CON1_RESET_VAL; + val &= ~(CTRL_GATEDURADJ_MASK); + writel(val, &phy0_ctrl->phy_con1); + writel(val, &phy1_ctrl->phy_con1); + + writel(CTRL_RDLVL_GATE_ENABLE, &dmc->rdlvl_config); + i = RDLVL_COMPLETE_TIMEOUT; + while ((readl(&dmc->phystatus) & + (RDLVL_COMPLETE_CHO | RDLVL_COMPLETE_CH1)) != + (RDLVL_COMPLETE_CHO | RDLVL_COMPLETE_CH1) && i > 0) { + /* + * TODO(waihong): Comment on how long this take to + * timeout + */ + sdelay(100); + i--; + } + if (!i) + return SETUP_ERR_RDLV_COMPLETE_TIMEOUT; + writel(CTRL_RDLVL_GATE_DISABLE, &dmc->rdlvl_config); + + writel(0, &phy0_ctrl->phy_con14); + writel(0, &phy1_ctrl->phy_con14); + + val = (mem->ctrl_start_point << + PHY_CON12_CTRL_START_POINT_SHIFT) | + (mem->ctrl_inc << PHY_CON12_CTRL_INC_SHIFT) | + (mem->ctrl_force << PHY_CON12_CTRL_FORCE_SHIFT) | + (mem->ctrl_start << PHY_CON12_CTRL_START_SHIFT) | + (mem->ctrl_dll_on << PHY_CON12_CTRL_DLL_ON_SHIFT) | + (mem->ctrl_ref << PHY_CON12_CTRL_REF_SHIFT); + writel(val, &phy0_ctrl->phy_con12); + writel(val, &phy1_ctrl->phy_con12); + + update_reset_dll(dmc, DDR_MODE_DDR3); + } + + /* Send PALL command */ + dmc_config_prech(mem, dmc); + + writel(mem->memcontrol, &dmc->memcontrol); + + /* Set DMC Concontrol and enable auto-refresh counter */ + writel(mem->concontrol | (mem->rd_fetch << CONCONTROL_RD_FETCH_SHIFT) + | (mem->aref_en << CONCONTROL_AREF_EN_SHIFT), &dmc->concontrol); + return 0; +} diff --git a/src/cpu/samsung/exynos5250/exynos_cache.c b/src/cpu/samsung/exynos5250/exynos_cache.c new file mode 100644 index 0000000..6944349 --- /dev/null +++ b/src/cpu/samsung/exynos5250/exynos_cache.c @@ -0,0 +1,90 @@ +/* + * Copyright (c) 2012 Samsung Electronics. + * Arun Mankuzhi arun.m@samsung.com + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +#include <common.h> +#include <asm/system.h> + +#include <armv7.h> + +enum l2_cache_params { + CACHE_TAG_RAM_SETUP = (1<<9), + CACHE_DATA_RAM_SETUP = (1<<5), + CACHE_TAG_RAM_LATENCY = (2<<6), + CACHE_DATA_RAM_LATENCY = (2<<0) +}; + + +/* FIXME(dhendrix): maybe move this to a romstage-specific file? */ +#ifdef __PRE_RAM__ +void enable_caches(void) +{ + /* Enable D-cache. I-cache is already enabled in start.S */ + dcache_enable(); +} +#endif + +/* + * Set L2 cache parameters + */ +static void exynos5_set_l2cache_params(void) +{ + unsigned int val = 0; + + asm volatile("mrc p15, 1, %0, c9, c0, 2\n" : "=r"(val)); + + val |= CACHE_TAG_RAM_SETUP | + CACHE_DATA_RAM_SETUP | + CACHE_TAG_RAM_LATENCY | + CACHE_DATA_RAM_LATENCY; + + asm volatile("mcr p15, 1, %0, c9, c0, 2\n" : : "r"(val)); +} + +/* + * Sets L2 cache related parameters before enabling data cache + */ +void v7_outer_cache_enable(void) +{ + exynos5_set_l2cache_params(); +} + +/* stubs so we don't need weak symbols in cache_v7.c */ +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) +{ +} diff --git a/src/cpu/samsung/exynos5250/lowlevel_init.S b/src/cpu/samsung/exynos5250/lowlevel_init.S new file mode 100644 index 0000000..883db9d --- /dev/null +++ b/src/cpu/samsung/exynos5250/lowlevel_init.S @@ -0,0 +1,32 @@ +/* + * Lowlevel setup for SMDK5250 board based on S5PC520 + * + * Copyright (C) 2012 Samsung Electronics + * + * 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 + */ + + .globl lowlevel_init +lowlevel_init: + /* + * Set the stack pointer, although it will be overwriten by the caller + * It seems we will not boot if this function is empty. + */ + ldr sp, =CONFIG_IRAM_STACK + mov pc, lr diff --git a/src/cpu/samsung/exynos5250/lowlevel_init_c.c b/src/cpu/samsung/exynos5250/lowlevel_init_c.c new file mode 100644 index 0000000..1480ca8 --- /dev/null +++ b/src/cpu/samsung/exynos5250/lowlevel_init_c.c @@ -0,0 +1,120 @@ +/* + * Lowlevel setup for SMDK5250 board based on S5PC520 + * + * Copyright (C) 2012 Samsung Electronics + * Copyright (c) 2012 The Chromium OS Authors. + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +#include <common.h> +#include <config.h> +#include <cpu/samsung/exynos-common/exynos5-common.h> +#include <cpu/samsung/exynos-common/spl.h> +#include <cpu/samsung/exynos5250/clock_init.h> +#include <cpu/samsung/exynos5250/cpu.h> +#include <cpu/samsung/exynos5250/dmc.h> +#include <cpu/samsung/exynos5250/pinmux.h> +#include <cpu/samsung/exynos5250/power.h> +#include <cpu/samsung/exynos5250/setup.h> +#include <cpu/samsung/exynos5250/tzpc.h> +#include "setup.h" + + +void do_barriers(void); /* FIXME: make gcc shut up about "no previous prototype" */ + +void do_barriers(void) +{ + /* + * The reason we don't write out the instructions dsb/isb/sev: + * While ARM Cortex-A8 supports ARM v7 instruction set (-march=armv7a), + * we compile with -march=armv5 to allow more compilers to work. + * For U-Boot code this has no performance impact. + */ + __asm__ __volatile__( +#if defined(__thumb__) + ".hword 0xF3BF, 0x8F4F\n" /* dsb; darn -march=armv5 */ + ".hword 0xF3BF, 0x8F6F\n" /* isb; darn -march=armv5 */ + ".hword 0xBF40\n" /* sev; darn -march=armv5 */ +#else + ".word 0xF57FF04F\n" /* dsb; darn -march=armv5 */ + ".word 0xF57FF06F\n" /* isb; darn -march=armv5 */ + ".word 0xE320F004\n" /* sev; darn -march=armv5 */ +#endif + ); +} + +/* These are the things we can do during low-level init */ +enum { + DO_WAKEUP = 1 << 0, + DO_UART = 1 << 1, + DO_CLOCKS = 1 << 2, + DO_POWER = 1 << 3, +}; + +int lowlevel_init_subsystems(void) +{ + uint32_t reset_status; + int actions = 0; + + do_barriers(); + + /* Setup cpu info which is needed to select correct register offsets */ + cpu_info_init(); + + reset_status = power_read_reset_status(); + + switch (reset_status) { + case S5P_CHECK_SLEEP: + actions = DO_CLOCKS | DO_WAKEUP; + break; + case S5P_CHECK_DIDLE: + case S5P_CHECK_LPA: + actions = DO_WAKEUP; + default: + /* This is a normal boot (not a wake from sleep) */ + actions = DO_UART | DO_CLOCKS | DO_POWER; + } + + if (actions & DO_POWER) + power_init(); + if (actions & DO_CLOCKS) + system_clock_init(); + if (actions & DO_UART) { + /* Set up serial UART so we can printf() */ +// exynos_pinmux_config(EXYNOS_UART, PINMUX_FLAG_NONE); + /* FIXME(dhendrix): add a function for mapping + CONFIG_CONSOLE_SERIAL_UART_ADDRESS to PERIPH_ID_UARTn */ + exynos_pinmux_config(PERIPH_ID_UART3, PINMUX_FLAG_NONE); + /* FIXME(dhendrix): serial_init() does not seem to + actually do anything !?!? */ +// serial_init(); + init_timer(); /* FIXME(dhendrix): was timer_init() */ + } + +/* FIXME(dhendrix): place this somewhere for ramstage... */ +#if 0 + if (actions & DO_CLOCKS) { + mem_ctrl_init(); + tzpc_init(); + } +#endif + + return actions & DO_WAKEUP; +} diff --git a/src/cpu/samsung/exynos5250/pinmux.c b/src/cpu/samsung/exynos5250/pinmux.c new file mode 100755 index 0000000..ef9d98a --- /dev/null +++ b/src/cpu/samsung/exynos5250/pinmux.c @@ -0,0 +1,303 @@ +/* + * Copyright (c) 2012 Samsung Electronics. + * Abhilash Kesavan a.kesavan@samsung.com + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +#include <common.h> +#include <arch/gpio.h> +#include <cpu/samsung/exynos5250/gpio.h> +#include <cpu/samsung/exynos5250/cpu.h> +#include <cpu/samsung/exynos5250/pinmux.h> +#include <cpu/samsung/exynos-common/sromc.h> + +int exynos_pinmux_config(enum periph_id peripheral, int flags) +{ + int i, start, count, start_ext, pin_ext, pin, drv; + + switch (peripheral) { + case PERIPH_ID_UART0: + case PERIPH_ID_UART1: + case PERIPH_ID_UART2: + case PERIPH_ID_UART3: + switch (peripheral) { + default: + case PERIPH_ID_UART0: + start = GPIO_A00; count = 4; + break; + case PERIPH_ID_UART1: + start = GPIO_A04; count = 4; + break; + case PERIPH_ID_UART2: + start = GPIO_A10; count = 4; + break; + case PERIPH_ID_UART3: + start = GPIO_A14; count = 2; + break; + } + for (i = start; i < start + count; i++) { + gpio_set_pull(i, EXYNOS_GPIO_PULL_NONE); + gpio_cfg_pin(i, EXYNOS_GPIO_FUNC(0x2)); + } + break; + case PERIPH_ID_SDMMC0: + case PERIPH_ID_SDMMC1: + case PERIPH_ID_SDMMC2: + case PERIPH_ID_SDMMC3: + pin = EXYNOS_GPIO_FUNC(0x2); + pin_ext = EXYNOS_GPIO_FUNC(0x2); + drv = EXYNOS_GPIO_DRV_4X; + switch (peripheral) { + default: + case PERIPH_ID_SDMMC0: + start = GPIO_C00; + start_ext = GPIO_C10; + break; + case PERIPH_ID_SDMMC1: + start = GPIO_C20; + start_ext = 0; + break; + case PERIPH_ID_SDMMC2: + start = GPIO_C30; + /* + * TODO: (alim.akhtar@samsung.com) + * add support for 8 bit mode (needs to be a per-board + * option, so in the FDT). + */ + start_ext = 0; + break; + case PERIPH_ID_SDMMC3: + /* + * TODO: Need to add defintions for GPC4 before + * enabling this. + */ + debug("SDMMC3 not supported yet"); + return -1; + } + if ((flags & PINMUX_FLAG_8BIT_MODE) && !start_ext) { + debug("SDMMC device %d does not support 8bit mode", + peripheral); + return -1; + } + if (flags & PINMUX_FLAG_8BIT_MODE) { + assert(peripheral == PERIPH_ID_SDMMC0); + for (i = 0; i <= 3; i++) { + gpio_cfg_pin(start_ext + i, pin_ext); + gpio_set_pull(start_ext + i, + EXYNOS_GPIO_PULL_UP); + gpio_set_drv(start_ext + i, drv); + } + } + for (i = 0; i < 2; i++) { + gpio_cfg_pin(start + i, pin); + gpio_set_pull(start + i, EXYNOS_GPIO_PULL_NONE); + gpio_set_drv(start + i, drv); + } + for (i = 2; i <= 6; i++) { + gpio_cfg_pin(start + i, pin); + gpio_set_pull(start + i, EXYNOS_GPIO_PULL_UP); + gpio_set_drv(start + i, drv); + } + break; + case PERIPH_ID_SROMC: + /* + * SROM:CS1 and EBI + * + * GPY0[0] SROM_CSn[0] + * GPY0[1] SROM_CSn[1](2) + * GPY0[2] SROM_CSn[2] + * GPY0[3] SROM_CSn[3] + * GPY0[4] EBI_OEn(2) + * GPY0[5] EBI_EEn(2) + * + * GPY1[0] EBI_BEn[0](2) + * GPY1[1] EBI_BEn[1](2) + * GPY1[2] SROM_WAIT(2) + * GPY1[3] EBI_DATA_RDn(2) + */ + gpio_cfg_pin(GPIO_Y00 + (flags & PINMUX_FLAG_BANK), + EXYNOS_GPIO_FUNC(2)); + gpio_cfg_pin(GPIO_Y04, EXYNOS_GPIO_FUNC(2)); + gpio_cfg_pin(GPIO_Y05, EXYNOS_GPIO_FUNC(2)); + + for (i = 2; i < 4; i++) + gpio_cfg_pin(GPIO_Y10 + i, EXYNOS_GPIO_FUNC(2)); + + /* + * EBI: 8 Addrss Lines + * + * GPY3[0] EBI_ADDR[0](2) + * GPY3[1] EBI_ADDR[1](2) + * GPY3[2] EBI_ADDR[2](2) + * GPY3[3] EBI_ADDR[3](2) + * GPY3[4] EBI_ADDR[4](2) + * GPY3[5] EBI_ADDR[5](2) + * GPY3[6] EBI_ADDR[6](2) + * GPY3[7] EBI_ADDR[7](2) + * + * EBI: 16 Data Lines + * + * GPY5[0] EBI_DATA[0](2) + * GPY5[1] EBI_DATA[1](2) + * GPY5[2] EBI_DATA[2](2) + * GPY5[3] EBI_DATA[3](2) + * GPY5[4] EBI_DATA[4](2) + * GPY5[5] EBI_DATA[5](2) + * GPY5[6] EBI_DATA[6](2) + * GPY5[7] EBI_DATA[7](2) + * + * GPY6[0] EBI_DATA[8](2) + * GPY6[1] EBI_DATA[9](2) + * GPY6[2] EBI_DATA[10](2) + * GPY6[3] EBI_DATA[11](2) + * GPY6[4] EBI_DATA[12](2) + * GPY6[5] EBI_DATA[13](2) + * GPY6[6] EBI_DATA[14](2) + * GPY6[7] EBI_DATA[15](2) + */ + for (i = 0; i < 8; i++) { + gpio_cfg_pin(GPIO_Y30 + i, EXYNOS_GPIO_FUNC(2)); + gpio_set_pull(GPIO_Y30 + i, EXYNOS_GPIO_PULL_UP); + + gpio_cfg_pin(GPIO_Y50 + i, EXYNOS_GPIO_FUNC(2)); + gpio_set_pull(GPIO_Y50 + i, EXYNOS_GPIO_PULL_UP); + + if (flags & PINMUX_FLAG_16BIT) { + gpio_cfg_pin(GPIO_Y60 + i, EXYNOS_GPIO_FUNC(2)); + gpio_set_pull(GPIO_Y60 + i, + EXYNOS_GPIO_PULL_UP); + } + } + break; + case PERIPH_ID_SPI0: + case PERIPH_ID_SPI1: + case PERIPH_ID_SPI2: + case PERIPH_ID_SPI3: { + int cfg; + + switch (peripheral) { + default: + case PERIPH_ID_SPI0: + start = GPIO_A20; + cfg = 0x2; + break; + case PERIPH_ID_SPI1: + start = GPIO_A24; + cfg = 0x2; + break; + case PERIPH_ID_SPI2: + start = GPIO_B11; + cfg = 0x5; + break; + case PERIPH_ID_SPI3: + start = GPIO_E00; + cfg = 0x2; + break; + } + + for (i = 0; i < 4; i++) + gpio_cfg_pin(start + i, EXYNOS_GPIO_FUNC(cfg)); + break; + } + case PERIPH_ID_SPI4: + for (i = 0; i < 2; i++) + gpio_cfg_pin(GPIO_F02 + i, EXYNOS_GPIO_FUNC(0x4)); + for (i = 2; i < 4; i++) + gpio_cfg_pin(GPIO_E02 + i, EXYNOS_GPIO_FUNC(0x4)); + break; + case PERIPH_ID_BACKLIGHT: + gpio_cfg_pin(GPIO_B20, EXYNOS_GPIO_OUTPUT); + gpio_set_value(GPIO_B20, 1); + break; + case PERIPH_ID_LCD: + gpio_cfg_pin(GPIO_Y25, EXYNOS_GPIO_OUTPUT); + gpio_set_value(GPIO_Y25, 1); + gpio_cfg_pin(GPIO_X15, EXYNOS_GPIO_OUTPUT); + gpio_set_value(GPIO_X15, 1); + gpio_cfg_pin(GPIO_X30, EXYNOS_GPIO_OUTPUT); + gpio_set_value(GPIO_X30, 1); + break; + case PERIPH_ID_I2C0: + gpio_cfg_pin(GPIO_B30, EXYNOS_GPIO_FUNC(0x2)); + gpio_cfg_pin(GPIO_B31, EXYNOS_GPIO_FUNC(0x2)); + gpio_set_pull(GPIO_B30, EXYNOS_GPIO_PULL_NONE); + gpio_set_pull(GPIO_B31, EXYNOS_GPIO_PULL_NONE); + break; + case PERIPH_ID_I2C1: + gpio_cfg_pin(GPIO_B32, EXYNOS_GPIO_FUNC(0x2)); + gpio_cfg_pin(GPIO_B33, EXYNOS_GPIO_FUNC(0x2)); + gpio_set_pull(GPIO_B32, EXYNOS_GPIO_PULL_NONE); + gpio_set_pull(GPIO_B33, EXYNOS_GPIO_PULL_NONE); + break; + case PERIPH_ID_I2C2: + gpio_cfg_pin(GPIO_A06, EXYNOS_GPIO_FUNC(0x3)); + gpio_cfg_pin(GPIO_A07, EXYNOS_GPIO_FUNC(0x3)); + gpio_set_pull(GPIO_A06, EXYNOS_GPIO_PULL_NONE); + gpio_set_pull(GPIO_A07, EXYNOS_GPIO_PULL_NONE); + break; + case PERIPH_ID_I2C3: + gpio_cfg_pin(GPIO_A12, EXYNOS_GPIO_FUNC(0x3)); + gpio_cfg_pin(GPIO_A13, EXYNOS_GPIO_FUNC(0x3)); + gpio_set_pull(GPIO_A12, EXYNOS_GPIO_PULL_NONE); + gpio_set_pull(GPIO_A13, EXYNOS_GPIO_PULL_NONE); + break; + case PERIPH_ID_I2C4: + gpio_cfg_pin(GPIO_A20, EXYNOS_GPIO_FUNC(0x3)); + gpio_cfg_pin(GPIO_A21, EXYNOS_GPIO_FUNC(0x3)); + gpio_set_pull(GPIO_A20, EXYNOS_GPIO_PULL_NONE); + gpio_set_pull(GPIO_A21, EXYNOS_GPIO_PULL_NONE); + break; + case PERIPH_ID_I2C5: + gpio_cfg_pin(GPIO_A22, EXYNOS_GPIO_FUNC(0x3)); + gpio_cfg_pin(GPIO_A23, EXYNOS_GPIO_FUNC(0x3)); + gpio_set_pull(GPIO_A22, EXYNOS_GPIO_PULL_NONE); + gpio_set_pull(GPIO_A23, EXYNOS_GPIO_PULL_NONE); + break; + case PERIPH_ID_I2C6: + gpio_cfg_pin(GPIO_B13, EXYNOS_GPIO_FUNC(0x4)); + gpio_cfg_pin(GPIO_B14, EXYNOS_GPIO_FUNC(0x4)); + break; + case PERIPH_ID_I2C7: + gpio_cfg_pin(GPIO_B22, EXYNOS_GPIO_FUNC(0x3)); + gpio_cfg_pin(GPIO_B23, EXYNOS_GPIO_FUNC(0x3)); + gpio_set_pull(GPIO_B22, EXYNOS_GPIO_PULL_NONE); + gpio_set_pull(GPIO_B23, EXYNOS_GPIO_PULL_NONE); + break; + case PERIPH_ID_DPHPD: + /* Set Hotplug detect for DP */ + gpio_cfg_pin(GPIO_X07, EXYNOS_GPIO_FUNC(0x3)); + + /* + * Hotplug detect should have an external pullup; disable the + * internal pulldown so they don't fight. + */ + gpio_set_pull(GPIO_X07, EXYNOS_GPIO_PULL_NONE); + break; + case PERIPH_ID_I2S1: + for (i = 0; i < 5; i++) + gpio_cfg_pin(GPIO_B00 + i, EXYNOS_GPIO_FUNC(0x02)); + break; + default: + debug("%s: invalid peripheral %d", __func__, peripheral); + return -1; + } + + return 0; +} diff --git a/src/cpu/samsung/exynos5250/power.c b/src/cpu/samsung/exynos5250/power.c new file mode 100644 index 0000000..45ad5de --- /dev/null +++ b/src/cpu/samsung/exynos5250/power.c @@ -0,0 +1,202 @@ +/* + * Power setup code for EXYNOS5 + * + * Copyright (C) 2012 Samsung Electronics + * + * 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 <arch/io.h> +#include <console/console.h> +#include <cpu/samsung/exynos5250/cpu.h> +#include <cpu/samsung/exynos5250/power.h> +#include <cpu/samsung/exynos5250/sysreg.h> +#include <cpu/samsung/exynos-common/spl.h> +#include <device/i2c.h> +#include <device/power/max77686.h> + +static void ps_hold_setup(void) +{ + struct exynos5_power *power = + (struct exynos5_power *)samsung_get_base_power(); + + /* Set PS-Hold high */ + setbits_le32(&power->ps_hold_ctrl, POWER_PS_HOLD_CONTROL_DATA_HIGH); +} + +void power_reset(void) +{ + struct exynos5_power *power = + (struct exynos5_power *)samsung_get_base_power(); + + /* Clear inform1 so there's no change we think we've got a wake reset */ + power->inform1 = 0; + + setbits_le32(&power->sw_reset, 1); +} + +/* This function never returns */ +void power_shutdown(void) +{ + struct exynos5_power *power = + (struct exynos5_power *)samsung_get_base_power(); + + clrbits_le32(&power->ps_hold_ctrl, POWER_PS_HOLD_CONTROL_DATA_HIGH); + + hang(); +} + +void power_enable_dp_phy(void) +{ + struct exynos5_power *power = + (struct exynos5_power *)samsung_get_base_power(); + + setbits_le32(&power->dptx_phy_control, DPTX_PHY_ENABLE); +} + +void power_enable_usb_phy(void) +{ + struct exynos5_sysreg *sysreg = + (struct exynos5_sysreg *)samsung_get_base_sysreg(); + struct exynos5_power *power = + (struct exynos5_power *)samsung_get_base_power(); + unsigned int phy_cfg; + + /* Setting USB20PHY_CONFIG register to USB 2.0 HOST link */ + phy_cfg = readl(&sysreg->usb20_phy_cfg); + if (phy_cfg & USB20_PHY_CFG_EN) { + debug("USB 2.0 HOST link already selected\n"); + } else { + phy_cfg |= USB20_PHY_CFG_EN; + writel(phy_cfg, &sysreg->usb20_phy_cfg); + } + + /* Enabling USBHOST_PHY */ + setbits_le32(&power->usb_host_phy_ctrl, POWER_USB_HOST_PHY_CTRL_EN); +} + +void power_disable_usb_phy(void) +{ + struct exynos5_power *power = + (struct exynos5_power *)samsung_get_base_power(); + + /* Disabling USBHost_PHY */ + clrbits_le32(&power->usb_host_phy_ctrl, POWER_USB_HOST_PHY_CTRL_EN); +} + +void power_enable_hw_thermal_trip(void) +{ + struct exynos5_power *power = + (struct exynos5_power *)samsung_get_base_power(); + + /* Enable HW thermal trip */ + setbits_le32(&power->ps_hold_ctrl, POWER_ENABLE_HW_TRIP); +} + +uint32_t power_read_reset_status(void) +{ + struct exynos5_power *power = + (struct exynos5_power *)samsung_get_base_power(); + + return power->inform1; +} + +void power_exit_wakeup(void) +{ + struct exynos5_power *power = + (struct exynos5_power *)samsung_get_base_power(); + typedef void (*resume_func)(void); + + ((resume_func)power->inform0)(); +} + +/** + * Initialize the pmic voltages to power up the system + * This also calls i2c_init so that we can program the pmic + * + * REG_ENABLE = 0, needed to set the buck/ldo enable bit ON + * + * @return Return 0 if ok, else -1 + */ +int power_init(void) +{ + int error = 0; + + /* FIXME(dhendrix): not necessary for initial bringup... */ +#if 0 +#ifdef CONFIG_SPL_BUILD + struct spl_machine_param *param = spl_get_machine_params(); + + /* Set the i2c register address base so i2c works before FDT */ + i2c_set_early_reg(param->i2c_base); +#endif +#endif + + ps_hold_setup(); + + /* FIXME(dhendrix): not necessary for initial bringup... */ +#if 0 + /* init the i2c so that we can program pmic chip */ + i2c_init(CONFIG_SYS_I2C_SPEED, CONFIG_SYS_I2C_SLAVE); + + /* + * We're using CR1616 coin cell battery that is non-rechargeable + * battery. But, BBCHOSTEN bit of the BBAT Charger Register in + * MAX77686 is enabled by default for charging coin cell. + * + * Also, we cannot meet the coin cell reverse current spec. in UL + * standard if BBCHOSTEN bit is enabled. + * + * Disable Coin BATT Charging + */ + error = max77686_disable_backup_batt(); + + error |= max77686_volsetting(PMIC_BUCK2, CONFIG_VDD_ARM_MV, + REG_ENABLE, MAX77686_MV); + error |= max77686_volsetting(PMIC_BUCK3, CONFIG_VDD_INT_UV, + REG_ENABLE, MAX77686_UV); + error |= max77686_volsetting(PMIC_BUCK1, CONFIG_VDD_MIF_MV, + REG_ENABLE, MAX77686_MV); + error |= max77686_volsetting(PMIC_BUCK4, CONFIG_VDD_G3D_MV, + REG_ENABLE, MAX77686_MV); + error |= max77686_volsetting(PMIC_LDO2, CONFIG_VDD_LDO2_MV, + REG_ENABLE, MAX77686_MV); + error |= max77686_volsetting(PMIC_LDO3, CONFIG_VDD_LDO3_MV, + REG_ENABLE, MAX77686_MV); + error |= max77686_volsetting(PMIC_LDO5, CONFIG_VDD_LDO5_MV, + REG_ENABLE, MAX77686_MV); + error |= max77686_volsetting(PMIC_LDO10, CONFIG_VDD_LDO10_MV, + REG_ENABLE, MAX77686_MV); +#endif + if (error != 0) + printk(BIOS_ERR, "power init failed\n"); + + return error; +} + +void power_enable_xclkout(void) +{ + struct exynos5_power *power = + (struct exynos5_power *)samsung_get_base_power(); + + /* use xxti for xclk out */ + clrsetbits_le32(&power->pmu_debug, PMU_DEBUG_CLKOUT_SEL_MASK, + PMU_DEBUG_XXTI); +} diff --git a/src/cpu/samsung/exynos5250/sata.c b/src/cpu/samsung/exynos5250/sata.c new file mode 100644 index 0000000..b3e464e --- /dev/null +++ b/src/cpu/samsung/exynos5250/sata.c @@ -0,0 +1,431 @@ +/* + * Copyright (c) 2012 The Chromium OS Authors. + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ +#include <ahci.h> +#include <common.h> +#include <fdtdec.h> +#include <scsi.h> +#include <asm/arch-exynos5/sata.h> +#include <asm/arch/pinmux.h> +#include <asm/errno.h> +#include <asm/gpio.h> +#include <asm/types.h> + +#define SATA_AHCI_AXI 0x122f0000 +#define SATA_PHCTRL_APB 0x12170000 +#define SATA_PHY_I2C_ABP 0x121d0000 +#define EXYNOS5_SATA_PHY_CONTROL (0x10040000 + 0x724) +#define S5P_PMU_SATA_PHY_CONTROL_EN 0x1 + +void * const phy_ctrl = (void *)SATA_PHCTRL_APB; +void * const phy_i2c_base = (void *)SATA_PHY_I2C_ABP; + +typedef unsigned char bool; +#define true 1 +#define false 0 + + +#define SATA_TIME_LIMIT 10000 +#define SATA_PHY_I2C_SLAVE_ADDRS 0x70 + +#define SATA_RESET 0x4 +#define RESET_CMN_RST_N (1 << 1) +#define LINK_RESET 0xF0000 + +#define SATA_MODE0 0x10 + +#define SATA_CTRL0 0x14 +#define CTRL0_P0_PHY_CALIBRATED_SEL (1 << 9) +#define CTRL0_P0_PHY_CALIBRATED (1 << 8) + +#define SATA_PHSATA_CTRLM 0xE0 +#define PHCTRLM_REF_RATE (1 << 1) +#define PHCTRLM_HIGH_SPEED (1 << 0) + +#define SATA_PHSATA_STATM 0xF0 +#define PHSTATM_PLL_LOCKED (1 << 0) + + +/********************** I2C**************/ +#define SATA_I2C_CON 0x00 +#define SATA_I2C_STAT 0x04 +#define SATA_I2C_ADDR 0x08 +#define SATA_I2C_DS 0x0C +#define SATA_I2C_LC 0x10 + +/* I2CCON reg */ +#define CON_ACKEN (1 << 7) +#define CON_CLK512 (1 << 6) +#define CON_CLK16 (~CON_CLK512) +#define CON_INTEN (1 << 5) +#define CON_INTPND (1 << 4) +#define CON_TXCLK_PS (0xF) + +/* I2CSTAT reg */ +#define STAT_MSTT (0x3 << 6) +#define STAT_BSYST (1 << 5) +#define STAT_RTEN (1 << 4) +#define STAT_LAST (1 << 0) + +#define LC_FLTR_EN (1 << 2) + +#define SATA_PHY_CON_RESET 0xF003F + +#define SCLK_SATA_FREQ (66 * MHZ) + + + +enum { + SATA_GENERATION1, + SATA_GENERATION2, + SATA_GENERATION3, +}; + +static bool sata_is_reg(void __iomem *base, u32 reg, u32 checkbit, u32 Status) +{ + if ((__raw_readl(base + reg) & checkbit) == Status) + return true; + else + return false; +} + +static bool wait_for_reg_status(void __iomem *base, u32 reg, u32 checkbit, + u32 Status) +{ + u32 time_limit_cnt = 0; + while (!sata_is_reg(base, reg, checkbit, Status)) { + if (time_limit_cnt == SATA_TIME_LIMIT) { + return false; + } + udelay(1000); + time_limit_cnt++; + } + return true; +} + + +static void sata_set_gen(u8 gen) +{ + __raw_writel(gen, phy_ctrl + SATA_MODE0); +} + +/* Address :I2C Address */ +static void sata_i2c_write_addrs(u8 data) +{ + __raw_writeb((data & 0xFE), phy_i2c_base + SATA_I2C_DS); +} + +static void sata_i2c_write_data(u8 data) +{ + __raw_writeb((data), phy_i2c_base + SATA_I2C_DS); +} + +static void sata_i2c_start(void) +{ + u32 val; + val = __raw_readl(phy_i2c_base + SATA_I2C_STAT); + val |= STAT_BSYST; + __raw_writel(val, phy_i2c_base + SATA_I2C_STAT); +} + +static void sata_i2c_stop(void) +{ + u32 val; + val = __raw_readl(phy_i2c_base + SATA_I2C_STAT); + val &= ~STAT_BSYST; + __raw_writel(val, phy_i2c_base + SATA_I2C_STAT); +} + +static bool sata_i2c_get_int_status(void) +{ + if ((__raw_readl(phy_i2c_base + SATA_I2C_CON)) & CON_INTPND) + return true; + else + return false; +} + +static bool sata_i2c_is_tx_ack(void) +{ + if ((__raw_readl(phy_i2c_base + SATA_I2C_STAT)) & STAT_LAST) + return false; + else + return true; +} + +static bool sata_i2c_is_bus_ready(void) +{ + if ((__raw_readl(phy_i2c_base + SATA_I2C_STAT)) & STAT_BSYST) + return false; + else + return true; +} + +static bool sata_i2c_wait_for_busready(u32 time_out) +{ + while (--time_out) { + if (sata_i2c_is_bus_ready()) + return true; + udelay(100); + } + return false; +} + +static bool sata_i2c_wait_for_tx_ack(u32 time_out) +{ + while (--time_out) { + if (sata_i2c_get_int_status()) { + if (sata_i2c_is_tx_ack()) + return true; + } + udelay(100); + } + return false; +} + +static void sata_i2c_clear_int_status(void) +{ + u32 val; + val = __raw_readl(phy_i2c_base + SATA_I2C_CON); + val &= ~CON_INTPND; + __raw_writel(val, phy_i2c_base + SATA_I2C_CON); +} + + +static void sata_i2c_set_ack_gen(bool enable) +{ + u32 val; + if (enable) { + val = (__raw_readl(phy_i2c_base + SATA_I2C_CON)) | CON_ACKEN; + __raw_writel(val, phy_i2c_base + SATA_I2C_CON); + } else { + val = __raw_readl(phy_i2c_base + SATA_I2C_CON); + val &= ~CON_ACKEN; + __raw_writel(val, phy_i2c_base + SATA_I2C_CON); + } + +} + +static void sata_i2c_set_master_tx(void) +{ + u32 val; + /* Disable I2C */ + val = __raw_readl(phy_i2c_base + SATA_I2C_STAT); + val &= ~STAT_RTEN; + __raw_writel(val, phy_i2c_base + SATA_I2C_STAT); + /* Clear Mode */ + val = __raw_readl(phy_i2c_base + SATA_I2C_STAT); + val &= ~STAT_MSTT; + __raw_writel(val, phy_i2c_base + SATA_I2C_STAT); + + sata_i2c_clear_int_status(); + /* interrupt disable */ + val = __raw_readl(phy_i2c_base + SATA_I2C_CON); + val &= ~CON_INTEN; + __raw_writel(val, phy_i2c_base + SATA_I2C_CON); + + /* Master, Send mode */ + val = __raw_readl(phy_i2c_base + SATA_I2C_STAT); + val |= STAT_MSTT; + __raw_writel(val, phy_i2c_base + SATA_I2C_STAT); + + /* interrupt enable */ + val = __raw_readl(phy_i2c_base + SATA_I2C_CON); + val |= CON_INTEN; + __raw_writel(val, phy_i2c_base + SATA_I2C_CON); + + /* Enable I2C */ + val = __raw_readl(phy_i2c_base + SATA_I2C_STAT); + val |= STAT_RTEN; + __raw_writel(val, phy_i2c_base + SATA_I2C_STAT); +} + +static void sata_i2c_init(void) +{ + u32 val; + + val = __raw_readl(phy_i2c_base + SATA_I2C_CON); + val &= CON_CLK16; + __raw_writel(val, phy_i2c_base + SATA_I2C_CON); + + val = __raw_readl(phy_i2c_base + SATA_I2C_CON); + val &= ~(CON_TXCLK_PS); + __raw_writel(val, phy_i2c_base + SATA_I2C_CON); + + val = __raw_readl(phy_i2c_base + SATA_I2C_CON); + val |= (2 & CON_TXCLK_PS); + __raw_writel(val, phy_i2c_base + SATA_I2C_CON); + + val = __raw_readl(phy_i2c_base + SATA_I2C_LC); + val &= ~(LC_FLTR_EN); + __raw_writel(val, phy_i2c_base + SATA_I2C_LC); + + sata_i2c_set_ack_gen(false); +} +static bool sata_i2c_send(u8 slave_addrs, u8 addrs, u8 ucData) +{ + s32 ret = 0; + if (!sata_i2c_wait_for_busready(SATA_TIME_LIMIT)) + return false; + + sata_i2c_init(); + sata_i2c_set_master_tx(); + + __raw_writel(SATA_PHY_CON_RESET, phy_ctrl + SATA_RESET); + sata_i2c_write_addrs(slave_addrs); + sata_i2c_start(); + if (!sata_i2c_wait_for_tx_ack(SATA_TIME_LIMIT)) { + ret = false; + goto STOP; + } + sata_i2c_write_data(addrs); + sata_i2c_clear_int_status(); + if (!sata_i2c_wait_for_tx_ack(SATA_TIME_LIMIT)) { + ret = false; + goto STOP; + } + sata_i2c_write_data(ucData); + sata_i2c_clear_int_status(); + if (!sata_i2c_wait_for_tx_ack(SATA_TIME_LIMIT)) { + ret = false; + goto STOP; + } + ret = true; + +STOP: + sata_i2c_stop(); + sata_i2c_clear_int_status(); + sata_i2c_wait_for_busready(SATA_TIME_LIMIT); + + return ret; +} + +static bool ahci_phy_init(void __iomem *mmio) +{ + u8 uCount, i = 0; + /* 0x3A for 40bit I/F */ + u8 reg_addrs[] = {0x22, 0x21, 0x3A}; + /* 0x0B for 40bit I/F */ + u8 default_setting_value[] = {0x30, 0x4f, 0x0B}; + + uCount = sizeof(reg_addrs)/sizeof(u8); + while (i < uCount) { + if (!sata_i2c_send(SATA_PHY_I2C_SLAVE_ADDRS, reg_addrs[i], + default_setting_value[i])) + return false; + i++; + } + return true; +} + +static int exynos5_ahci_init(void __iomem *mmio) +{ + int val, ret; + + __raw_writel(S5P_PMU_SATA_PHY_CONTROL_EN, EXYNOS5_SATA_PHY_CONTROL); + + val = 0; + __raw_writel(val, phy_ctrl + SATA_RESET); + val = __raw_readl(phy_ctrl + SATA_RESET); + val |= 0x3D; + __raw_writel(val, phy_ctrl + SATA_RESET); + + val = __raw_readl(phy_ctrl + SATA_RESET); + val |= LINK_RESET; + __raw_writel(val, phy_ctrl + SATA_RESET); + + val = __raw_readl(phy_ctrl + SATA_RESET); + val |= RESET_CMN_RST_N; + __raw_writel(val, phy_ctrl + SATA_RESET); + + val = __raw_readl(phy_ctrl + SATA_PHSATA_CTRLM); + val &= ~PHCTRLM_REF_RATE; + __raw_writel(val, phy_ctrl + SATA_PHSATA_CTRLM); + + /* High speed enable for Gen3 */ + val = __raw_readl(phy_ctrl + SATA_PHSATA_CTRLM); + val |= PHCTRLM_HIGH_SPEED; + __raw_writel(val, phy_ctrl + SATA_PHSATA_CTRLM); + + /* Port0 is available */ + __raw_writel(0x1, mmio + HOST_PORTS_IMPL); + + ret = ahci_phy_init(mmio); + + val = __raw_readl(phy_ctrl + SATA_CTRL0); + val |= CTRL0_P0_PHY_CALIBRATED_SEL|CTRL0_P0_PHY_CALIBRATED; + __raw_writel(val, phy_ctrl + SATA_CTRL0); + sata_set_gen(SATA_GENERATION3); + + /* release cmu reset */ + val = __raw_readl(phy_ctrl + SATA_RESET); + val &= ~RESET_CMN_RST_N; + __raw_writel(val, phy_ctrl + SATA_RESET); + + val = __raw_readl(phy_ctrl + SATA_RESET); + val |= RESET_CMN_RST_N; + __raw_writel(val, phy_ctrl + SATA_RESET); + + if (wait_for_reg_status(phy_ctrl, SATA_PHSATA_STATM, + PHSTATM_PLL_LOCKED, 1)) { + return ret; + } + return 0; +} + +static int exynos5_sata_enable_power(const void *blob) +{ + int node; + struct fdt_gpio_state gpio; + + node = fdtdec_next_compatible(blob, 0, COMPAT_GOOGLE_SATA); + if (node >= 0 && + fdtdec_decode_gpio(blob, node, "enable-gpios", &gpio) == 0) { + gpio_cfg_pin(gpio.gpio, EXYNOS_GPIO_OUTPUT); + gpio_set_value(gpio.gpio, 1); + return 0; + } + return -ENODEV; +} + +static void exynos5_enable_clock_gates(void) +{ + /* Turn on all SATA clock gates & DMA gates. */ + const unsigned cmu_toppart = 0x10020000; + const unsigned addr = cmu_toppart + 0x944; + const unsigned sata_clocks = (1 << 25) | (1 << 24) | (1 << 6); + const unsigned dma_clocks = (2 << 1) | (1 << 1); + const unsigned clk_gate_ip_fsys = readl(addr); + writel(clk_gate_ip_fsys | sata_clocks | dma_clocks, addr); +} + +int exynos5_sata_init(const void *blob) +{ + if (exynos5_sata_enable_power(blob) == 0) { + exynos5_enable_clock_gates(); + + if (exynos5_ahci_init((void *)SATA_AHCI_AXI)) { + ahci_init(SATA_AHCI_AXI); + scsi_scan(1); + return 0; + } + } + return -ENODEV; +} diff --git a/src/cpu/samsung/exynos5250/setup.h b/src/cpu/samsung/exynos5250/setup.h index 5e59232..bb438c5 100644 --- a/src/cpu/samsung/exynos5250/setup.h +++ b/src/cpu/samsung/exynos5250/setup.h @@ -25,6 +25,10 @@ #ifndef _SMDK5250_SETUP_H #define _SMDK5250_SETUP_H
+struct exynos5_dmc; +enum ddr_mode; +struct exynos5_phy_control; + /* TZPC : Register Offsets */ #define TZPC0_BASE 0x10100000 #define TZPC1_BASE 0x10110000 @@ -683,7 +687,8 @@ enum { };
/* Functions common between LPDDR2 and DDR3 */ -void sdelay(unsigned long); +/* FIXME(dhendrix): conflicts with arch system.h version of sdelay()... */ +//void sdelay(unsigned long);
/* CPU info initialization code */ void cpu_info_init(void); diff --git a/src/cpu/samsung/exynos5250/soc.c b/src/cpu/samsung/exynos5250/soc.c new file mode 100644 index 0000000..be28d8c --- /dev/null +++ b/src/cpu/samsung/exynos5250/soc.c @@ -0,0 +1,47 @@ +/* + * This file is part of the coreboot project. + * + * Copyright (C) 2011 The Chromium OS 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 + */ + +#include <cpu/samsung/exynos5250/cpu.h> +#include <cpu/samsung/exynos5250/periph.h> + +#include <cpu/samsung/exynos5250/uart.h> + +enum periph_id exynos5_get_periph_id(unsigned base_addr) +{ + enum periph_id id = PERIPH_ID_NONE; + + switch (base_addr) { + case EXYNOS5_UART0_BASE: + id = PERIPH_ID_UART0; + break; + case EXYNOS5_UART1_BASE: + id = PERIPH_ID_UART1; + break; + case EXYNOS5_UART2_BASE: + id = PERIPH_ID_UART2; + break; + case EXYNOS5_UART3_BASE: + id = PERIPH_ID_UART3; + break; + default: + break; + } + + return id; +} diff --git a/src/cpu/samsung/exynos5250/spl.c b/src/cpu/samsung/exynos5250/spl.c new file mode 100644 index 0000000..00b584a --- /dev/null +++ b/src/cpu/samsung/exynos5250/spl.c @@ -0,0 +1,41 @@ +/* + * Copyright (C) 2012 Samsung Electronics + * + * 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): file unneeded? */ +#if 0 +#include <asm/types.h> +#include <asm/arch-exynos/cpu.h> +#include <asm/arch-exynos/spl.h> + +/* Get the u-boot size from the SPL parameter table */ +unsigned int exynos_get_uboot_size(void) +{ + struct spl_machine_param *param = spl_get_machine_params(); + + return param->uboot_size; +} + +/* Get the boot device from the SPL parameter table */ +enum boot_mode exynos_get_boot_device(void) +{ + struct spl_machine_param *param = spl_get_machine_params(); + + return param->boot_source; +} +#endif diff --git a/src/cpu/samsung/exynos5250/tzpc_init.c b/src/cpu/samsung/exynos5250/tzpc_init.c new file mode 100644 index 0000000..370c2ed --- /dev/null +++ b/src/cpu/samsung/exynos5250/tzpc_init.c @@ -0,0 +1,57 @@ +/* + * Lowlevel setup for SMDK5250 board based on S5PC520 + * + * Copyright (C) 2012 Samsung Electronics + * + * 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 <cpu/samsung/exynos5250/cpu.h> +#include <asm/arch/dmc.h> +#include <asm/arch/tzpc.h> +#include"setup.h" + +/* Setting TZPC[TrustZone Protection Controller] */ +void tzpc_init(void) +{ + struct exynos5_tzpc *tzpc; + unsigned int addr; + + for (addr = TZPC0_BASE; addr <= TZPC9_BASE; addr += TZPC_BASE_OFFSET) { + tzpc = (struct exynos5_tzpc *)addr; + + if (addr == TZPC0_BASE) + writel(R0SIZE, &tzpc->r0size); + + writel(DECPROTXSET, &tzpc->decprot0set); + writel(DECPROTXSET, &tzpc->decprot1set); + + if (addr == TZPC9_BASE) { + + /* TODO: Add comment here describing the numerical values + * used below. + */ + writel(0xf0, &tzpc->decprot2set); + writel(0x50, &tzpc->decprot3set); + } else { + writel(DECPROTXSET, &tzpc->decprot2set); + writel(DECPROTXSET, &tzpc->decprot3set); + } + } +} diff --git a/src/cpu/samsung/exynos5250/uart.c b/src/cpu/samsung/exynos5250/uart.c new file mode 100644 index 0000000..55131c9 --- /dev/null +++ b/src/cpu/samsung/exynos5250/uart.c @@ -0,0 +1,235 @@ +/* + * (C) Copyright 2009 SAMSUNG Electronics + * Minkyu Kang mk7.kang@samsung.com + * Heungjun Kim riverful.kim@samsung.com + * + * based on drivers/serial/s3c64xx.c + * + * 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 <linux/compiler.h> +#include <uart.h> +#include <arch/io.h> +//#include <asm/arch-exynos/spl.h> +//#include <asm/global_data.h> +//#include <fdtdec.h> +//#include <serial.h> + +#include <console/console.h> /* for __console definition */ + +#include <cpu/samsung/exynos-common/exynos5-common.h> +#include <cpu/samsung/exynos5250/clk.h> +#include <cpu/samsung/exynos5250/uart.h> + +#define RX_FIFO_COUNT_MASK 0xff +#define RX_FIFO_FULL_MASK (1 << 8) +#define TX_FIFO_FULL_MASK (1 << 24) + +/* FIXME(dhendrix): exynos5 has 4 UARTs and its functions in u-boot take a + base_port argument. However console_driver functions do not. */ +static uint32_t base_port = CONFIG_CONSOLE_SERIAL_UART_ADDRESS; +#if 0 +/* Information about a serial port */ +struct fdt_serial { + u32 base_addr; /* address of registers in physical memory */ + u8 port_id; /* uart port number */ + u8 enabled; /* 1 if enabled, 0 if disabled */ +} config = { + -1U +}; +#endif + +#if 0 +static inline struct s5p_uart *s5p_get_base_uart(int dev_index) +{ + /* FIXME: there should be an assertion here if dev_index is >3 */ + return (struct s5p_uart *)(EXYNOS5_UART0_BASE + (0x10000 * dev_index)); +} +#endif + +/* + * The coefficient, used to calculate the baudrate on S5P UARTs is + * calculated as + * C = UBRDIV * 16 + number_of_set_bits_in_UDIVSLOT + * however, section 31.6.11 of the datasheet doesn't recomment using 1 for 1, + * 3 for 2, ... (2^n - 1) for n, instead, they suggest using these constants: + */ +static const int udivslot[] = { + 0, + 0x0080, + 0x0808, + 0x0888, + 0x2222, + 0x4924, + 0x4a52, + 0x54aa, + 0x5555, + 0xd555, + 0xd5d5, + 0xddd5, + 0xdddd, + 0xdfdd, + 0xdfdf, + 0xffdf, +}; + +static void serial_setbrg_dev(void) +{ +// struct s5p_uart *const uart = s5p_get_base_uart(dev_index); + struct s5p_uart *uart = (struct s5p_uart *)base_port; + u32 uclk; + u32 baudrate = CONFIG_TTYS0_BAUD; + u32 val; + enum periph_id periph; + + periph = exynos5_get_periph_id(base_port); + uclk = clock_get_periph_rate(periph); + val = uclk / baudrate; + + writel(val / 16 - 1, &uart->ubrdiv); + + /* + * FIXME(dhendrix): the original uart.h had a "br_rest" value which + * does not seem relevant to the exynos5250... not entirely sure + * where/if we need to worry about it here + */ +#if 0 + if (s5p_uart_divslot()) + writew(udivslot[val % 16], &uart->rest.slot); + else + writeb(val % 16, &uart->rest.value); +#endif +} + +/* + * Initialise the serial port with the given baudrate. The settings + * are always 8 data bits, no parity, 1 stop bit, no start bits. + */ +static void exynos5_init_dev(void) +{ +// struct s5p_uart *const uart = s5p_get_base_uart(dev_index); + struct s5p_uart *uart = (struct s5p_uart *)base_port; + + /* enable FIFOs */ + writel(0x1, &uart->ufcon); + writel(0, &uart->umcon); + /* 8N1 */ + writel(0x3, &uart->ulcon); + /* No interrupts, no DMA, pure polling */ + writel(0x245, &uart->ucon); + + serial_setbrg_dev(); +} + +static int exynos5_uart_err_check(int op) +{ + //struct s5p_uart *const uart = s5p_get_base_uart(dev_index); + struct s5p_uart *uart = (struct s5p_uart *)base_port; + unsigned int mask; + + /* + * UERSTAT + * Break Detect [3] + * Frame Err [2] : receive operation + * Parity Err [1] : receive operation + * Overrun Err [0] : receive operation + */ + if (op) + mask = 0x8; + else + mask = 0xf; + + return readl(&uart->uerstat) & mask; +} + +/* + * Read a single byte from the serial port. Returns 1 on success, 0 + * otherwise. When the function is succesfull, the character read is + * written into its argument c. + */ +static unsigned char exynos5_uart_rx_byte(void) +{ +// struct s5p_uart *const uart = s5p_get_base_uart(dev_index); + struct s5p_uart *uart = (struct s5p_uart *)base_port; + + /* wait for character to arrive */ + while (!(readl(&uart->ufstat) & (RX_FIFO_COUNT_MASK | + RX_FIFO_FULL_MASK))) { + if (exynos5_uart_err_check(0)) + return 0; + } + + return readb(&uart->urxh) & 0xff; +} + +/* + * Output a single byte to the serial port. + */ +/* FIXME: ordering of arguments for coreboot v. u-boot for tx_byte */ +//static void exynos5_tx_byte(const char c, const int dev_index) +static void exynos5_uart_tx_byte(unsigned char data) +{ +// struct s5p_uart *const uart = s5p_get_base_uart(dev_index); + struct s5p_uart *uart = (struct s5p_uart *)base_port; + + /* wait for room in the tx FIFO */ + while ((readl(uart->ufstat) & TX_FIFO_FULL_MASK)) { + if (exynos5_uart_err_check(1)) + return; + } + + writeb(data, &uart->utxh); +} + +#ifndef __PRE_RAM__ +static const struct console_driver exynos5_uart_console __console = { +//static const struct console_driver exynos5_uart_console __console = { +#if 0 + void (*init)(void); + void (*tx_byte)(unsigned char byte); + void (*tx_flush)(void); + unsigned char (*rx_byte)(void); + int (*tst_byte)(void); +#endif + .init = exynos5_init_dev, + .tx_byte = exynos5_uart_tx_byte, +// .tx_flush = exynos5_uart_tx_flush, + .rx_byte = exynos5_uart_rx_byte, +// .tst_byte = exynos5_uart_tst_byte, +}; +#else +/* for romstage_console... */ +//void (*uart_init)(void) = exynos5_init_dev; +//unsigned char (*uart_rx_byte)(unsigned base_port) = exynos5_uart_rx_byte; +//void (*uart_tx_byte)(unsigned base_port, unsigned char data) = exynos5_uart_tx_byte; +/* FIXME: trivial wrappers */ +void uart_init() +{ + exynos5_init_dev(); +} + +unsigned char uart_rx_byte() +{ + return exynos5_uart_rx_byte(); +} + +void uart_tx_byte(unsigned char data) +{ + exynos5_uart_tx_byte(data); +} +#endif diff --git a/src/cpu/samsung/s5p-common/Makefile.inc b/src/cpu/samsung/s5p-common/Makefile.inc new file mode 100644 index 0000000..9747f0d --- /dev/null +++ b/src/cpu/samsung/s5p-common/Makefile.inc @@ -0,0 +1,12 @@ +romstage-y += cpu_info.c +romstage-y += pwm.c # needed by timer.c +romstage-y += s5p_gpio.c +romstage-y += timer.c + +#romstage-y += sromc.c +#romstage-y += wdt.c + +ramstage-y += cpu_info.c +ramstage-y += pwm.c # needed by timer.c +ramstage-y += timer.c +ramstage-y += s5p_gpio.c diff --git a/src/cpu/samsung/s5p-common/Makefile.uboot b/src/cpu/samsung/s5p-common/Makefile.uboot new file mode 100644 index 0000000..f975f3f --- /dev/null +++ b/src/cpu/samsung/s5p-common/Makefile.uboot @@ -0,0 +1,49 @@ +# +# Copyright (C) 2009 Samsung Electronics +# Minkyu Kang mk7.kang@samsung.com +# +# See file CREDITS for list of people who contributed to this +# project. +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License as +# published by the Free Software Foundation; either version 2 of +# the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, +# MA 02111-1307 USA +# + +include $(TOPDIR)/config.mk + +LIB = $(obj)libs5p-common.o + +COBJS-y += cpu_info.o +COBJS-y += timer.o +COBJS-y += sromc.o +COBJS-y += wdt.o +COBJS-$(CONFIG_PWM) += pwm.o + +SRCS := $(SOBJS:.o=.S) $(COBJS:.o=.c) +OBJS := $(addprefix $(obj),$(COBJS-y) $(SOBJS)) + +all: $(obj).depend $(LIB) + +$(LIB): $(OBJS) + $(call cmd_link_o_target, $(OBJS)) + +######################################################################### + +# defines $(obj).depend target +include $(SRCTREE)/rules.mk + +sinclude $(obj).depend + +######################################################################### diff --git a/src/cpu/samsung/s5p-common/cpu_info.c b/src/cpu/samsung/s5p-common/cpu_info.c new file mode 100644 index 0000000..4a66d22 --- /dev/null +++ b/src/cpu/samsung/s5p-common/cpu_info.c @@ -0,0 +1,128 @@ +/* + * Copyright (C) 2009 Samsung Electronics + * Minkyu Kang mk7.kang@samsung.com + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ +#include <common.h> +#if 0 +#include <asm/io.h> +#include <asm/arch/clk.h> +#include <asm/arch/clock.h> +#include <asm/arch/dmc.h> +#endif +#include <arch/io.h> + +#include <cpu/samsung/s5p-common/clk.h> +#include <cpu/samsung/s5p-common/clock.h> +#include <cpu/samsung/s5p-common/cpu.h> + +#include <cpu/samsung/exynos5250/dmc.h> +#include <cpu/samsung/exynos-common/cpu.h> /* for EXYNOS_PRO_ID */ + +/* FIXME(dhendrix): consolidate samsung ID code/#defines to a common location */ +#include <cpu/samsung/exynos5250/setup.h> /* cpu_info_init() prototype */ + +/* + * The following CPU infos are initialized in lowlevel_init(). They should be + * put in the .data section. Otherwise, a compile will put them in the .bss + * section since they don't have initial values. The relocation code which + * runs after lowlevel_init() will reset them to zero. + */ +unsigned int s5p_cpu_id __attribute__((section(".data"))); +unsigned int s5p_cpu_rev __attribute__((section(".data"))); + +void cpu_info_init(void) +{ + s5p_set_cpu_id(); +} + +int s5p_get_cpu_id(void) +{ + return s5p_cpu_id; +} + +int s5p_get_cpu_rev(void) +{ + return s5p_cpu_rev; +} + +void s5p_set_cpu_id(void) +{ + s5p_cpu_id = readl(EXYNOS_PRO_ID); + s5p_cpu_id = (0xC000 | ((s5p_cpu_id & 0x00FFF000) >> 12)); + + /* + * 0xC200: EXYNOS4210 EVT0 + * 0xC210: EXYNOS4210 EVT1 + */ + if (s5p_cpu_id == 0xC200) { + s5p_cpu_id |= 0x10; + s5p_cpu_rev = 0; + } else if (s5p_cpu_id == 0xC210) { + s5p_cpu_rev = 1; + } +} + +#ifdef CONFIG_DISPLAY_CPUINFO +int print_cpuinfo(void) +{ + char buf[32]; + + printf("CPU: S5P%X @ %sMHz\n", + s5p_cpu_id, strmhz(buf, get_arm_clk())); + + return 0; +} +#endif + +#ifndef CONFIG_SPL_BUILD +void board_show_dram(ulong size) +{ + enum ddr_mode mem_type; + unsigned frequency_mhz; + unsigned arm_freq; + enum mem_manuf mem_manuf; + char buf[32]; + int ret; + + /* Get settings from the fdt */ + ret = clock_get_mem_selection(&mem_type, &frequency_mhz, + &arm_freq, &mem_manuf); + if (ret) + panic("Invalid DRAM information"); + + puts("DRAM: "); + print_size(size, " "); + printf("%s %s @ %sMHz", + clock_get_mem_manuf_name(mem_manuf), + clock_get_mem_type_name(mem_type), + strmhz(buf, frequency_mhz)); + putc('\n'); +} +#endif + +#ifdef CONFIG_ARCH_CPU_INIT +int arch_cpu_init(void) +{ + cpu_info_init(); + + return 0; +} +#endif diff --git a/src/cpu/samsung/s5p-common/pwm.c b/src/cpu/samsung/s5p-common/pwm.c new file mode 100644 index 0000000..356c78e --- /dev/null +++ b/src/cpu/samsung/s5p-common/pwm.c @@ -0,0 +1,205 @@ +/* + * Copyright (C) 2011 Samsung Electronics + * + * Donghwa Lee dh09.lee@samsung.com + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +#include <common.h> +//#include <pwm.h> +#include <arch/io.h> +//#include <arch/pwm.h> +//#include <arch/clk.h> +/* FIXME(dhendrix): this is a godawful mess of similar-but-different includes... */ +#include <cpu/samsung/exynos-common/clk.h> +#include <cpu/samsung/exynos5250/cpu.h> +#include <cpu/samsung/exynos5250/periph.h> +#include <cpu/samsung/s5p-common/pwm.h> +#include <cpu/samsung/s5p-common/clk.h> +//#include <arch/periph.h> + +int pwm_enable(int pwm_id) +{ + const struct s5p_timer *pwm = + (struct s5p_timer *)samsung_get_base_timer(); + unsigned long tcon; + + tcon = readl(&pwm->tcon); + tcon |= TCON_START(pwm_id); + + writel(tcon, &pwm->tcon); + + return 0; +} + +int pwm_check_enabled(int pwm_id) +{ + const struct s5p_timer *pwm = + (struct s5p_timer *)samsung_get_base_timer(); + const unsigned long tcon = readl(&pwm->tcon); + + return tcon & TCON_START(pwm_id); +} + +void pwm_disable(int pwm_id) +{ + const struct s5p_timer *pwm = + (struct s5p_timer *)samsung_get_base_timer(); + unsigned long tcon; + + tcon = readl(&pwm->tcon); + tcon &= ~TCON_START(pwm_id); + + writel(tcon, &pwm->tcon); +} + +static unsigned long pwm_calc_tin(int pwm_id, unsigned long freq) +{ + unsigned long tin_parent_rate; + unsigned int div; + + tin_parent_rate = clock_get_periph_rate(PERIPH_ID_PWM0); + + for (div = 2; div <= 16; div *= 2) { + if ((tin_parent_rate / (div << 16)) < freq) + return tin_parent_rate / div; + } + + return tin_parent_rate / 16; +} + +#define NS_IN_SEC 1000000000UL + +int pwm_config(int pwm_id, int duty_ns, int period_ns) +{ + const struct s5p_timer *pwm = + (struct s5p_timer *)samsung_get_base_timer(); + unsigned int offset; + unsigned long tin_rate; + unsigned long tin_ns; + unsigned long frequency; + unsigned long tcon; + unsigned long tcnt; + unsigned long tcmp; + + /* + * We currently avoid using 64bit arithmetic by using the + * fact that anything faster than 1GHz is easily representable + * by 32bits. + */ + if (period_ns > NS_IN_SEC || duty_ns > NS_IN_SEC || period_ns == 0) + return -1; +// return -ERANGE; + + if (duty_ns > period_ns) + return -1; +// return -EINVAL; + + frequency = NS_IN_SEC / period_ns; + + /* Check to see if we are changing the clock rate of the PWM */ + tin_rate = pwm_calc_tin(pwm_id, frequency); + + tin_ns = NS_IN_SEC / tin_rate; + tcnt = period_ns / tin_ns; + + /* Note, counters count down */ + tcmp = duty_ns / tin_ns; + tcmp = tcnt - tcmp; + + /* Update the PWM register block. */ + offset = pwm_id * 3; + if (pwm_id < 4) { + writel(tcnt, &pwm->tcntb0 + offset); + writel(tcmp, &pwm->tcmpb0 + offset); + } + + tcon = readl(&pwm->tcon); + tcon |= TCON_UPDATE(pwm_id); + if (pwm_id < 4) + tcon |= TCON_AUTO_RELOAD(pwm_id); + else + tcon |= TCON4_AUTO_RELOAD; + writel(tcon, &pwm->tcon); + + tcon &= ~TCON_UPDATE(pwm_id); + writel(tcon, &pwm->tcon); + + return 0; +} + +int pwm_init(int pwm_id, int div, int invert) +{ + u32 val; + const struct s5p_timer *pwm = + (struct s5p_timer *)samsung_get_base_timer(); + unsigned long ticks_per_period; + unsigned int offset, prescaler; + + /* + * Timer Freq(HZ) = + * PWM_CLK / { (prescaler_value + 1) * (divider_value) } + */ + + val = readl(&pwm->tcfg0); + if (pwm_id < 2) { + prescaler = PRESCALER_0; + val &= ~0xff; + val |= (prescaler & 0xff); + } else { + prescaler = PRESCALER_1; + val &= ~(0xff << 8); + val |= (prescaler & 0xff) << 8; + } + writel(val, &pwm->tcfg0); + val = readl(&pwm->tcfg1); + val &= ~(0xf << MUX_DIV_SHIFT(pwm_id)); + val |= (div & 0xf) << MUX_DIV_SHIFT(pwm_id); + writel(val, &pwm->tcfg1); + + + if (pwm_id == 4) { + /* + * TODO(sjg): Use this as a countdown timer for now. We count + * down from the maximum value to 0, then reset. + */ + ticks_per_period = -1UL; + } else { + const unsigned long pwm_hz = 1000; + unsigned long timer_rate_hz = clock_get_periph_rate( + PERIPH_ID_PWM0) / ((prescaler + 1) * (1 << div)); + + ticks_per_period = timer_rate_hz / pwm_hz; + } + + /* set count value */ + offset = pwm_id * 3; + + writel(ticks_per_period, &pwm->tcntb0 + offset); + + val = readl(&pwm->tcon) & ~(0xf << TCON_OFFSET(pwm_id)); + if (invert && (pwm_id < 4)) + val |= TCON_INVERTER(pwm_id); + writel(val, &pwm->tcon); + + pwm_enable(pwm_id); + + return 0; +} diff --git a/src/cpu/samsung/s5p-common/s5p_gpio.c b/src/cpu/samsung/s5p-common/s5p_gpio.c new file mode 100644 index 0000000..e90ee2f --- /dev/null +++ b/src/cpu/samsung/s5p-common/s5p_gpio.c @@ -0,0 +1,490 @@ +/* + * (C) Copyright 2009 Samsung Electronics + * Minkyu Kang mk7.kang@samsung.com + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +/* FIXME(dhendrix): fix this up so it doesn't require a bunch of #ifdefs... */ +#include <common.h> +//#include <arch/io.h> +#include <arch/gpio.h> +#include <console/console.h> +#include <cpu/samsung/s5p-common/gpio.h> +#include <cpu/samsung/exynos-common/gpio.h> +#include <cpu/samsung/exynos5250/gpio.h> /* FIXME: for gpio_decode_number prototype */ + +#define CON_MASK(x) (0xf << ((x) << 2)) +#define CON_SFR(x, v) ((v) << ((x) << 2)) + +#define DAT_MASK(x) (0x1 << (x)) +#define DAT_SET(x) (0x1 << (x)) + +#define PULL_MASK(x) (0x3 << ((x) << 1)) +#define PULL_MODE(x, v) ((v) << ((x) << 1)) + +#define DRV_MASK(x) (0x3 << ((x) << 1)) +#define DRV_SET(x, m) ((m) << ((x) << 1)) +#define RATE_MASK(x) (0x1 << (x + 16)) +#define RATE_SET(x) (0x1 << (x + 16)) + +struct gpio_info { + unsigned int reg_addr; /* Address of register for this part */ + unsigned int max_gpio; /* Maximum GPIO in this part */ +}; + +#ifdef CONFIG_CPU_SAMSUNG_EXYNOS5 + +#include <cpu/samsung/exynos5250/cpu.h> +static const struct gpio_info gpio_data[EXYNOS_GPIO_NUM_PARTS] = { + { EXYNOS5_GPIO_PART1_BASE, GPIO_MAX_PORT_PART_1 }, + { EXYNOS5_GPIO_PART2_BASE, GPIO_MAX_PORT_PART_2 }, + { EXYNOS5_GPIO_PART3_BASE, GPIO_MAX_PORT_PART_3 }, + { EXYNOS5_GPIO_PART4_BASE, GPIO_MAX_PORT_PART_4 }, + { EXYNOS5_GPIO_PART5_BASE, GPIO_MAX_PORT_PART_5 }, + { EXYNOS5_GPIO_PART6_BASE, GPIO_MAX_PORT }, +}; + +#define HAVE_GENERIC_GPIO + +#elif defined(CONFIG_CPU_SAMSUNG_EXYNOS4) + +static const struct gpio_info gpio_data[EXYNOS_GPIO_NUM_PARTS] = { + { EXYNOS4_GPIO_PART1_BASE, GPIO_MAX_PORT_PART_1 }, + { EXYNOS4_GPIO_PART2_BASE, GPIO_MAX_PORT_PART_2 }, + { EXYNOS4_GPIO_PART3_BASE, GPIO_MAX_PORT_PART_3 }, +}; + +#define HAVE_GENERIC_GPIO + +#endif + +/* This macro gets gpio pin offset from 0..7 */ +#define GPIO_BIT(x) ((x) & 0x7) + +//#ifdef HAVE_GENERIC_GPIO +static struct s5p_gpio_bank *gpio_get_bank(unsigned int gpio) +{ + const struct gpio_info *data; + unsigned int upto; + int i; + + for (i = upto = 0, data = gpio_data; i < EXYNOS_GPIO_NUM_PARTS; + i++, upto = data->max_gpio, data++) { + if (gpio < data->max_gpio) { + struct s5p_gpio_bank *bank; + + bank = (struct s5p_gpio_bank *)data->reg_addr; + bank += (gpio - upto) / GPIO_PER_BANK; + return bank; + } + } + +#ifndef CONFIG_SPL_BUILD + assert(gpio < GPIO_MAX_PORT); /* ...which it will not be */ +#endif + return NULL; +} +//#endif + +/* TODO: Deprecation this interface in favour of asm-generic/gpio.h */ +void s5p_gpio_cfg_pin(struct s5p_gpio_bank *bank, int gpio, int cfg) +{ + unsigned int value; + + value = readl(&bank->con); + value &= ~CON_MASK(gpio); + value |= CON_SFR(gpio, cfg); + writel(value, &bank->con); +} + +void s5p_gpio_direction_output(struct s5p_gpio_bank *bank, int gpio, int en) +{ + unsigned int value; + + s5p_gpio_cfg_pin(bank, gpio, EXYNOS_GPIO_OUTPUT); + + value = readl(&bank->dat); + value &= ~DAT_MASK(gpio); + if (en) + value |= DAT_SET(gpio); + writel(value, &bank->dat); +} + +void s5p_gpio_direction_input(struct s5p_gpio_bank *bank, int gpio) +{ + s5p_gpio_cfg_pin(bank, gpio, EXYNOS_GPIO_INPUT); +} + +void s5p_gpio_set_value(struct s5p_gpio_bank *bank, int gpio, int en) +{ + unsigned int value; + + value = readl(&bank->dat); + value &= ~DAT_MASK(gpio); + if (en) + value |= DAT_SET(gpio); + writel(value, &bank->dat); +} + +unsigned int s5p_gpio_get_value(struct s5p_gpio_bank *bank, int gpio) +{ + unsigned int value; + + value = readl(&bank->dat); + return !!(value & DAT_MASK(gpio)); +} + +void s5p_gpio_set_pull(struct s5p_gpio_bank *bank, int gpio, int mode) +{ + unsigned int value; + + value = readl(&bank->pull); + value &= ~PULL_MASK(gpio); + + switch (mode) { + case EXYNOS_GPIO_PULL_DOWN: + case EXYNOS_GPIO_PULL_UP: + value |= PULL_MODE(gpio, mode); + break; + default: + break; + } + + writel(value, &bank->pull); +} + +void s5p_gpio_set_drv(struct s5p_gpio_bank *bank, int gpio, int mode) +{ + unsigned int value; + + value = readl(&bank->drv); + value &= ~DRV_MASK(gpio); + + switch (mode) { + case EXYNOS_GPIO_DRV_1X: + case EXYNOS_GPIO_DRV_2X: + case EXYNOS_GPIO_DRV_3X: + case EXYNOS_GPIO_DRV_4X: + value |= DRV_SET(gpio, mode); + break; + default: + return; + } + + writel(value, &bank->drv); +} + +void s5p_gpio_set_rate(struct s5p_gpio_bank *bank, int gpio, int mode) +{ + unsigned int value; + + value = readl(&bank->drv); + value &= ~RATE_MASK(gpio); + + switch (mode) { + case EXYNOS_GPIO_DRV_FAST: + case EXYNOS_GPIO_DRV_SLOW: + value |= RATE_SET(gpio); + break; + default: + return; + } + + writel(value, &bank->drv); +} + +/* Common GPIO API - only available on Exynos5 */ +/* FIXME(dhendrix): If this stuff is really only applicable to exynos5, + move it to a more sensible location. */ +#ifdef HAVE_GENERIC_GPIO + +void gpio_cfg_pin(int gpio, int cfg) +{ + unsigned int value; + struct s5p_gpio_bank *bank = gpio_get_bank(gpio); + + value = readl(&bank->con); + value &= ~CON_MASK(GPIO_BIT(gpio)); + value |= CON_SFR(GPIO_BIT(gpio), cfg); + writel(value, &bank->con); +} + +static int gpio_get_cfg(int gpio) +{ + struct s5p_gpio_bank *bank = gpio_get_bank(gpio); + int shift = GPIO_BIT(gpio) << 2; + + return (readl(&bank->con) & CON_MASK(GPIO_BIT(gpio))) >> shift; +} + +void gpio_set_pull(int gpio, int mode) +{ + unsigned int value; + struct s5p_gpio_bank *bank = gpio_get_bank(gpio); + + value = readl(&bank->pull); + value &= ~PULL_MASK(GPIO_BIT(gpio)); + + switch (mode) { + case EXYNOS_GPIO_PULL_DOWN: + case EXYNOS_GPIO_PULL_UP: + value |= PULL_MODE(GPIO_BIT(gpio), mode); + break; + default: + break; + } + + writel(value, &bank->pull); +} + +void gpio_set_drv(int gpio, int mode) +{ + unsigned int value; + struct s5p_gpio_bank *bank = gpio_get_bank(gpio); + + value = readl(&bank->drv); + value &= ~DRV_MASK(GPIO_BIT(gpio)); + + switch (mode) { + case EXYNOS_GPIO_DRV_1X: + case EXYNOS_GPIO_DRV_2X: + case EXYNOS_GPIO_DRV_3X: + case EXYNOS_GPIO_DRV_4X: + value |= DRV_SET(GPIO_BIT(gpio), mode); + break; + default: + return; + } + + writel(value, &bank->drv); +} + +void gpio_set_rate(int gpio, int mode) +{ + unsigned int value; + struct s5p_gpio_bank *bank = gpio_get_bank(gpio); + + value = readl(&bank->drv); + value &= ~RATE_MASK(GPIO_BIT(gpio)); + + switch (mode) { + case EXYNOS_GPIO_DRV_FAST: + case EXYNOS_GPIO_DRV_SLOW: + value |= RATE_SET(GPIO_BIT(gpio)); + break; + default: + return; + } + + writel(value, &bank->drv); +} + +int gpio_request(unsigned gpio, const char *label) +{ + return 0; +} + +int gpio_free(unsigned gpio) +{ + return 0; +} + +int gpio_direction_input(unsigned gpio) +{ + gpio_cfg_pin(gpio, EXYNOS_GPIO_INPUT); + + return 0; +} + +int gpio_direction_output(unsigned gpio, int value) +{ + unsigned int val; + struct s5p_gpio_bank *bank = gpio_get_bank(gpio); + + gpio_cfg_pin(gpio, EXYNOS_GPIO_OUTPUT); + + val = readl(&bank->dat); + val &= ~DAT_MASK(GPIO_BIT(gpio)); + if (value) + val |= DAT_SET(GPIO_BIT(gpio)); + writel(val, &bank->dat); + + return 0; +} + +int gpio_get_value(unsigned gpio) +{ + unsigned int value; + struct s5p_gpio_bank *bank = gpio_get_bank(gpio); + + value = readl(&bank->dat); + return !!(value & DAT_MASK(GPIO_BIT(gpio))); +} + +int gpio_set_value(unsigned gpio, int value) +{ + unsigned int val; + struct s5p_gpio_bank *bank = gpio_get_bank(gpio); + + val = readl(&bank->dat); + val &= ~DAT_MASK(GPIO_BIT(gpio)); + if (value) + val |= DAT_SET(GPIO_BIT(gpio)); + writel(val, &bank->dat); + + return 0; +} +#else + +static int s5p_gpio_get_pin(unsigned gpio) +{ + return gpio % GPIO_PER_BANK; +} + +/* + * If we have the old-style GPIO numbering setup, use these functions + * which don't necessary provide sequentially increasing GPIO numbers. + */ +static struct s5p_gpio_bank *s5p_gpio_get_bank(unsigned gpio) +{ + int bank = gpio / GPIO_PER_BANK; + bank *= sizeof(struct s5p_gpio_bank); + + return (struct s5p_gpio_bank *) (s5p_gpio_base(gpio) + bank); +} + +int gpio_request(unsigned gpio, const char *label) +{ + return 0; +} + +int gpio_free(unsigned gpio) +{ + return 0; +} + +int gpio_direction_input(unsigned gpio) +{ + s5p_gpio_direction_input(s5p_gpio_get_bank(gpio), + s5p_gpio_get_pin(gpio)); + return 0; +} + +int gpio_direction_output(unsigned gpio, int value) +{ + s5p_gpio_direction_output(s5p_gpio_get_bank(gpio), + s5p_gpio_get_pin(gpio), value); + return 0; +} + +int gpio_get_value(unsigned gpio) +{ + return (int) s5p_gpio_get_value(s5p_gpio_get_bank(gpio), + s5p_gpio_get_pin(gpio)); +} + +int gpio_set_value(unsigned gpio, int value) +{ + s5p_gpio_set_value(s5p_gpio_get_bank(gpio), + s5p_gpio_get_pin(gpio), value); + + return 0; +} + +#endif /* HAVE_GENERIC_GPIO */ + +/* + * Add a delay here to give the lines time to settle + * TODO(sjg): 1us does not always work, 2 is stable, so use 5 to be safe + * Come back to this and sort out what the datasheet says + */ +#define GPIO_DELAY_US 5 + +/* FIXME(dhendrix): this should probably go to a more generic location */ +int gpio_decode_number(unsigned gpio_list[], int count) +{ + int result = 0; + int multiplier = 1; + int value, high, low; + int gpio, i; + + for (i = 0; i < count; i++) { + gpio = gpio_list[i]; + if (gpio >= GPIO_MAX_PORT) + return -1; + gpio_direction_input(gpio); + gpio_set_pull(gpio, EXYNOS_GPIO_PULL_UP); + udelay(GPIO_DELAY_US); + high = gpio_get_value(gpio); + gpio_set_pull(gpio, EXYNOS_GPIO_PULL_DOWN); + udelay(GPIO_DELAY_US); + low = gpio_get_value(gpio); + + if (high && low) /* external pullup */ + value = 2; + else if (!high && !low) /* external pulldown */ + value = 1; + else /* floating */ + value = 0; + + /* + * Check if line is externally pulled high and + * configure the internal pullup to match. For + * floating and pulldowns, the GPIO is already + * configured with an internal pulldown from the + * above test. + */ + if (value == 2) + gpio_set_pull(gpio, EXYNOS_GPIO_PULL_UP); + + result += value * multiplier; + multiplier *= 3; + } + + return result; +} + +static const char *get_cfg_name(int cfg) +{ + static char name[8]; + + if (cfg == EXYNOS_GPIO_INPUT) + return "input"; + else if (cfg == EXYNOS_GPIO_OUTPUT) + return "output"; + printk(BIOS_INFO, "func %d", cfg); +// sprintf(name, "func %d", cfg); + + return name; +} + +/* + * Display Exynos GPIO information + */ +void gpio_info(void) +{ + unsigned gpio; + + for (gpio = 0; gpio < GPIO_MAX_PORT; gpio++) { + int cfg = gpio_get_cfg(gpio); + + printk(BIOS_INFO, "GPIO_%-3d: %s", gpio, get_cfg_name(cfg)); + if (cfg == EXYNOS_GPIO_INPUT || cfg == EXYNOS_GPIO_OUTPUT) + printk(BIOS_INFO, ", value = %d", gpio_get_value(gpio)); + printk(BIOS_INFO, "\n"); + } +} diff --git a/src/cpu/samsung/s5p-common/sromc.c b/src/cpu/samsung/s5p-common/sromc.c new file mode 100644 index 0000000..091e8d1 --- /dev/null +++ b/src/cpu/samsung/s5p-common/sromc.c @@ -0,0 +1,49 @@ +/* + * Copyright (C) 2010 Samsung Electronics + * Naveen Krishna Ch ch.naveen@samsung.com + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +#include <common.h> +#include <asm/io.h> +#include <asm/arch/sromc.h> + +/* + * s5p_config_sromc() - select the proper SROMC Bank and configure the + * band width control and bank control registers + * srom_bank - SROM + * srom_bw_conf - SMC Band witdh reg configuration value + * srom_bc_conf - SMC Bank Control reg configuration value + */ +void s5p_config_sromc(u32 srom_bank, u32 srom_bw_conf, u32 srom_bc_conf) +{ + u32 tmp; + struct s5p_sromc *srom = + (struct s5p_sromc *)samsung_get_base_sromc(); + + /* Configure SMC_BW register to handle proper SROMC bank */ + tmp = srom->bw; + tmp &= ~(0xF << (srom_bank * 4)); + tmp |= srom_bw_conf; + srom->bw = tmp; + + /* Configure SMC_BC register */ + srom->bc[srom_bank] = srom_bc_conf; +} diff --git a/src/cpu/samsung/s5p-common/timer.c b/src/cpu/samsung/s5p-common/timer.c new file mode 100644 index 0000000..91dcc6d --- /dev/null +++ b/src/cpu/samsung/s5p-common/timer.c @@ -0,0 +1,153 @@ +/* + * Copyright (C) 2009 Samsung Electronics + * Heungjun Kim riverful.kim@samsung.com + * Inki Dae inki.dae@samsung.com + * Minkyu Kang mk7.kang@samsung.com + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +#include <common.h> +#include <arch/io.h> +//#include <cpu/samsung/exynos5250/pwm.h> +//#include <cpu/samsung/exynos5250/clk.h> +#include <cpu/samsung/s5p-common/pwm.h> +#include <cpu/samsung/s5p-common/clk.h> +#include <cpu/samsung/exynos5250/cpu.h> +#include <cpu/samsung/exynos-common/exynos5-common.h> + +//#include <pwm.h> + +//DECLARE_GLOBAL_DATA_PTR; +static unsigned long long timer_reset_value; +static unsigned long lastinc; + +/* macro to read the 16 bit timer */ +static inline struct s5p_timer *s5p_get_base_timer(void) +{ + return (struct s5p_timer *)samsung_get_base_timer(); +} + +/** + * Read the countdown timer. + * + * This operates at 1MHz and counts downwards. It will wrap about every + * hour (2^32 microseconds). + * + * @return current value of timer + */ +static unsigned long timer_get_us_down(void) +{ + struct s5p_timer *const timer = s5p_get_base_timer(); + + return readl(&timer->tcnto4); +} + +int init_timer(void) +{ + /* Timer may have been enabled in SPL */ + if (!pwm_check_enabled(4)) { + /* PWM Timer 4 */ + pwm_init(4, MUX_DIV_4, 0); + pwm_config(4, 100000, 100000); + pwm_enable(4); +#ifndef CONFIG_SPL_BUILD + /* Use this as the current monotonic time in us */ + //gd->timer_reset_value = 0; + timer_reset_value = 0; + + /* Use this as the last timer value we saw */ + //gd->lastinc = timer_get_us_down(); + lastinc = timer_get_us_down(); +#endif + } + + return 0; +} + +/* + * timer without interrupts + */ +unsigned long get_timer(unsigned long base) +{ + ulong now = timer_get_us_down(); + + /* + * Increment the time by the amount elapsed since the last read. + * The timer may have wrapped around, but it makes no difference to + * our arithmetic here. + */ +#if 0 + gd->timer_reset_value += gd->lastinc - now; + gd->lastinc = now; + + /* Divide by 1000 to convert from us to ms */ + return gd->timer_reset_value / 1000 - base; +#endif + timer_reset_value += lastinc - now; + lastinc = now; + + /* Divide by 1000 to convert from us to ms */ + return timer_reset_value / 1000 - base; +} + +unsigned long timer_get_us(void) +{ + struct s5p_timer *const timer = s5p_get_base_timer(); + unsigned long now_downward_us = readl(&timer->tcnto4); + + /* + * Note that this timer counts downward. The pre-SPL process (BL1) + * takes about 100ms, so add this in here. + */ + return CONFIG_SPL_TIME_US - now_downward_us; +} + +/* delay x useconds */ +void __udelay(unsigned long usec) +{ + unsigned long count_value; + + count_value = timer_get_us_down(); + while ((int)(count_value - timer_get_us_down()) < (int)usec) + ; +} + +/* + * This function is derived from PowerPC code (read timebase as long long). + * On ARM it just returns the timer value. + */ +unsigned long long get_ticks(void) +{ + return get_timer(0); +} + +/* + * This function is derived from PowerPC code (timebase clock frequency). + * On ARM it returns the number of timer ticks per second. + */ +unsigned long get_tbclk(void) +{ + return CONFIG_SYS_HZ; +} + +unsigned long timer_get_boot_us(void) +{ + return timer_get_us(); +} diff --git a/src/cpu/samsung/s5p-common/wdt.c b/src/cpu/samsung/s5p-common/wdt.c new file mode 100644 index 0000000..94acc1e --- /dev/null +++ b/src/cpu/samsung/s5p-common/wdt.c @@ -0,0 +1,59 @@ +/* + * Copyright (C) 2012 Samsung Electronics + * Minkyu Kang mk7.kang@samsung.com + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +#include <common.h> +#include <asm/io.h> +#include <asm/arch/watchdog.h> + +#define PRESCALER_VAL 255 + +void wdt_stop(void) +{ + struct s5p_watchdog *wdt = + (struct s5p_watchdog *)samsung_get_base_watchdog(); + unsigned int wtcon; + + wtcon = readl(&wdt->wtcon); + wtcon &= ~(WTCON_EN | WTCON_INT | WTCON_RESET); + + writel(wtcon, &wdt->wtcon); +} + +void wdt_start(unsigned int timeout) +{ + struct s5p_watchdog *wdt = + (struct s5p_watchdog *)samsung_get_base_watchdog(); + unsigned int wtcon; + + wdt_stop(); + + wtcon = readl(&wdt->wtcon); + wtcon |= (WTCON_EN | WTCON_CLK(WTCON_CLK_128)); + wtcon &= ~WTCON_INT; + wtcon |= WTCON_RESET; + wtcon |= WTCON_PRESCALER(PRESCALER_VAL); + + writel(timeout, &wdt->wtdat); + writel(timeout, &wdt->wtcnt); + writel(wtcon, &wdt->wtcon); +} diff --git a/src/drivers/Kconfig b/src/drivers/Kconfig index ef38f34..ca94d2b 100644 --- a/src/drivers/Kconfig +++ b/src/drivers/Kconfig @@ -33,3 +33,4 @@ source src/drivers/realtek/Kconfig source src/drivers/sil/Kconfig source src/drivers/spi/Kconfig source src/drivers/trident/Kconfig +source src/drivers/maxim/Kconfig diff --git a/src/drivers/Makefile.inc b/src/drivers/Makefile.inc index a02b705..65800f0 100644 --- a/src/drivers/Makefile.inc +++ b/src/drivers/Makefile.inc @@ -30,4 +30,5 @@ subdirs-y += ics subdirs-y += spi subdirs-y += ipmi subdirs-y += elog +subdirs-y += maxim subdirs-$(CONFIG_ARCH_X86) += pc80 diff --git a/src/drivers/maxim/Kconfig b/src/drivers/maxim/Kconfig new file mode 100644 index 0000000..84ace13 --- /dev/null +++ b/src/drivers/maxim/Kconfig @@ -0,0 +1,5 @@ +config DRIVER_MAXIM_77686 + bool "Maxim 77686" + default n + help + Maxim 77686 power regulator diff --git a/src/drivers/maxim/Makefile.inc b/src/drivers/maxim/Makefile.inc new file mode 100644 index 0000000..3fc7104 --- /dev/null +++ b/src/drivers/maxim/Makefile.inc @@ -0,0 +1,20 @@ +## +## This file is part of the coreboot project. +## +## Copyright (C) 2012 The ChromiumOS Authors +## +## 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 +## + +driver-$(CONFIG_DRIVER_MAXIM_77686) += max77686.c diff --git a/src/drivers/maxim/max77686.c b/src/drivers/maxim/max77686.c new file mode 100644 index 0000000..6c24240 --- /dev/null +++ b/src/drivers/maxim/max77686.c @@ -0,0 +1,257 @@ +/* + * Copyright (C) 2012 Samsung Electronics + * Alim Akhtar alim.akhtar@samsung.com + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +#include <common.h> +#include <i2c.h> +#include <max77686.h> + +/* Chip register numbers (not exported from this module) */ +enum { + REG_BBAT = 0x7e, + + /* Bits for BBAT */ + BBAT_BBCHOSTEN_MASK = 1 << 0, + BBAT_BBCVS_SHIFT = 3, + BBAT_BBCVS_MASK = 3 << BBAT_BBCVS_SHIFT, +}; + +/* + * Max77686 parameters values + * see max77686.h for parameters details + */ +struct max77686_para max77686_param[] = {/*{regnum, vol_addr, vol_bitpos, + vol_bitmask, reg_enaddr, reg_enbitpos, reg_enbitmask, reg_enbiton, + reg_enbitoff, vol_min, vol_div}*/ + {PMIC_BUCK1, 0x11, 0x0, 0x3F, 0x10, 0x0, 0x3, 0x3, 0x0, 750, 50000}, + {PMIC_BUCK2, 0x14, 0x0, 0xFF, 0x12, 0x4, 0x3, 0x1, 0x0, 600, 12500}, + {PMIC_BUCK3, 0x1E, 0x0, 0xFF, 0x1C, 0x4, 0x3, 0x1, 0x0, 600, 12500}, + {PMIC_BUCK4, 0x28, 0x0, 0xFF, 0x26, 0x4, 0x3, 0x1, 0x0, 600, 12500}, + {PMIC_BUCK5, 0x31, 0x0, 0x3F, 0x30, 0x0, 0x3, 0x3, 0x0, 750, 50000}, + {PMIC_BUCK6, 0x33, 0x0, 0x3F, 0x32, 0x0, 0x3, 0x3, 0x0, 750, 50000}, + {PMIC_BUCK7, 0x35, 0x0, 0x3F, 0x34, 0x0, 0x3, 0x3, 0x0, 750, 50000}, + {PMIC_BUCK8, 0x37, 0x0, 0x3F, 0x36, 0x0, 0x3, 0x3, 0x0, 750, 50000}, + {PMIC_BUCK9, 0x39, 0x0, 0x3F, 0x38, 0x0, 0x3, 0x3, 0x0, 750, 50000}, + {PMIC_LDO1, 0x40, 0x0, 0x3F, 0x40, 0x6, 0x3, 0x3, 0x0, 800, 25000}, + {PMIC_LDO2, 0x41, 0x0, 0x3F, 0x41, 0x6, 0x3, 0x1, 0x0, 800, 25000}, + {PMIC_LDO3, 0x42, 0x0, 0x3F, 0x42, 0x6, 0x3, 0x3, 0x0, 800, 50000}, + {PMIC_LDO4, 0x43, 0x0, 0x3F, 0x43, 0x6, 0x3, 0x3, 0x0, 800, 50000}, + {PMIC_LDO5, 0x44, 0x0, 0x3F, 0x44, 0x6, 0x3, 0x3, 0x0, 800, 50000}, + {PMIC_LDO6, 0x45, 0x0, 0x3F, 0x45, 0x6, 0x3, 0x1, 0x0, 800, 25000}, + {PMIC_LDO7, 0x46, 0x0, 0x3F, 0x46, 0x6, 0x3, 0x1, 0x0, 800, 25000}, + {PMIC_LDO8, 0x47, 0x0, 0x3F, 0x47, 0x6, 0x3, 0x1, 0x0, 800, 25000}, + {PMIC_LDO9, 0x48, 0x0, 0x3F, 0x48, 0x6, 0x3, 0x3, 0x0, 800, 50000}, + {PMIC_LDO10, 0x49, 0x0, 0x3F, 0x49, 0x6, 0x3, 0x1, 0x0, 800, 50000}, + {PMIC_LDO11, 0x4A, 0x0, 0x3F, 0x4A, 0x6, 0x3, 0x1, 0x0, 800, 50000}, + {PMIC_LDO12, 0x4B, 0x0, 0x3F, 0x4B, 0x6, 0x3, 0x1, 0x0, 800, 50000}, + {PMIC_LDO13, 0x4C, 0x0, 0x3F, 0x4C, 0x6, 0x3, 0x3, 0x0, 800, 50000}, + {PMIC_LDO14, 0x4D, 0x0, 0x3F, 0x4D, 0x6, 0x3, 0x1, 0x0, 800, 50000}, + {PMIC_LDO15, 0x4E, 0x0, 0x3F, 0x4E, 0x6, 0x3, 0x1, 0x0, 800, 25000}, + {PMIC_LDO16, 0x4F, 0x0, 0x3F, 0x4F, 0x6, 0x3, 0x1, 0x0, 800, 50000}, + {PMIC_LDO17, 0x50, 0x0, 0x3F, 0x50, 0x6, 0x3, 0x3, 0x0, 800, 50000}, + {PMIC_LDO18, 0x51, 0x0, 0x3F, 0x51, 0x6, 0x3, 0x3, 0x0, 800, 50000}, + {PMIC_LDO19, 0x52, 0x0, 0x3F, 0x52, 0x6, 0x3, 0x3, 0x0, 800, 50000}, + {PMIC_LDO20, 0x53, 0x0, 0x3F, 0x53, 0x6, 0x3, 0x3, 0x0, 800, 50000}, + {PMIC_LDO21, 0x54, 0x0, 0x3F, 0x54, 0x6, 0x3, 0x3, 0x0, 800, 50000}, + {PMIC_LDO22, 0x55, 0x0, 0x3F, 0x55, 0x6, 0x3, 0x3, 0x0, 800, 50000}, + {PMIC_LDO23, 0x56, 0x0, 0x3F, 0x56, 0x6, 0x3, 0x3, 0x0, 800, 50000}, + {PMIC_LDO24, 0x57, 0x0, 0x3F, 0x57, 0x6, 0x3, 0x3, 0x0, 800, 50000}, + {PMIC_LDO25, 0x58, 0x0, 0x3F, 0x58, 0x6, 0x3, 0x3, 0x0, 800, 50000}, + {PMIC_LDO26, 0x59, 0x0, 0x3F, 0x59, 0x6, 0x3, 0x3, 0x0, 800, 50000}, + {PMIC_EN32KHZ_CP, 0x0, 0x0, 0x0, 0x7F, 0x1, 0x1, 0x1, 0x0, 0x0, 0x0}, +}; + +/* + * Write a value to a register + * + * @param chip_addr i2c addr for max77686 + * @param reg reg number to write + * @param val value to be written + * + */ +static inline int max77686_i2c_write(unsigned char chip_addr, + unsigned int reg, unsigned char val) +{ + return i2c_write(chip_addr, reg, 1, &val, 1); +} + +/* + * Read a value from a register + * + * @param chip_addr i2c addr for max77686 + * @param reg reg number to write + * @param val value to be written + * + */ +static inline int max77686_i2c_read(unsigned char chip_addr, + unsigned int reg, unsigned char *val) +{ + return i2c_read(chip_addr, reg, 1, val, 1); +} + +/* + * Enable the max77686 register + * + * @param reg register number of buck/ldo to be enabled + * @param enable enable or disable bit + * + * REG_DISABLE = 0, + needed to set the buck/ldo enable bit OFF + * @return Return 0 if ok, else -1 + */ +static int max77686_enablereg(enum max77686_regnum reg, int enable) +{ + struct max77686_para *pmic; + unsigned char read_data; + int ret; + + pmic = &max77686_param[reg]; + + ret = max77686_i2c_read(MAX77686_I2C_ADDR, pmic->reg_enaddr, + &read_data); + if (ret != 0) { + debug("max77686 i2c read failed.\n"); + return -1; + } + + if (enable == REG_DISABLE) { + clrbits_8(&read_data, + pmic->reg_enbitmask << pmic->reg_enbitpos); + } else { + clrsetbits_8(&read_data, + pmic->reg_enbitmask << pmic->reg_enbitpos, + pmic->reg_enbiton << pmic->reg_enbitpos); + } + + ret = max77686_i2c_write(MAX77686_I2C_ADDR, + pmic->reg_enaddr, read_data); + if (ret != 0) { + debug("max77686 i2c write failed.\n"); + return -1; + } + + return 0; +} + +static int max77686_do_volsetting(enum max77686_regnum reg, unsigned int volt, + int enable, int volt_units) +{ + struct max77686_para *pmic; + unsigned char read_data; + int vol_level = 0; + int ret; + + pmic = &max77686_param[reg]; + + if (pmic->vol_addr == 0) { + debug("not a voltage register.\n"); + return -1; + } + + ret = max77686_i2c_read(MAX77686_I2C_ADDR, pmic->vol_addr, &read_data); + if (ret != 0) { + debug("max77686 i2c read failed.\n"); + return -1; + } + + if (volt_units == MAX77686_UV) + vol_level = volt - pmic->vol_min * 1000; + else + vol_level = (volt - pmic->vol_min) * 1000; + + if (vol_level < 0) { + debug("Not a valid voltage level to set\n"); + return -1; + } + vol_level /= pmic->vol_div; + + clrsetbits_8(&read_data, pmic->vol_bitmask << pmic->vol_bitpos, + vol_level << pmic->vol_bitpos); + + ret = max77686_i2c_write(MAX77686_I2C_ADDR, pmic->vol_addr, read_data); + if (ret != 0) { + debug("max77686 i2c write failed.\n"); + return -1; + } + + ret = max77686_enablereg(reg, enable); + if (ret != 0) { + debug("Failed to enable buck/ldo.\n"); + return -1; + } + + return 0; +} + +int max77686_volsetting(enum max77686_regnum reg, unsigned int volt, + int enable, int volt_units) +{ + int old_bus = i2c_get_bus_num(); + int ret; + + i2c_set_bus_num(0); + ret = max77686_do_volsetting(reg, volt, enable, volt_units); + i2c_set_bus_num(old_bus); + return ret; +} + +int max77686_enable_32khz_cp(void) +{ + i2c_set_bus_num(0); + return max77686_enablereg(PMIC_EN32KHZ_CP, REG_ENABLE); +} + +int max77686_disable_backup_batt(void) +{ + unsigned char val; + int ret; + + i2c_set_bus_num(0); + ret = max77686_i2c_read(MAX77686_I2C_ADDR, REG_BBAT, &val); + if (ret) { + debug("max77686 i2c read failed\n"); + return ret; + } + + /* If we already have the correct values, exit */ + if ((val & (BBAT_BBCVS_MASK | BBAT_BBCHOSTEN_MASK)) == + BBAT_BBCVS_MASK) + return 0; + + /* First disable charging */ + val &= ~BBAT_BBCHOSTEN_MASK; + ret = max77686_i2c_write(MAX77686_I2C_ADDR, REG_BBAT, val); + if (ret) { + debug("max77686 i2c write failed\n"); + return -1; + } + + /* Finally select 3.5V to minimize power consumption */ + val |= BBAT_BBCVS_MASK; + ret = max77686_i2c_write(MAX77686_I2C_ADDR, REG_BBAT, val); + if (ret) { + debug("max77686 i2c write failed\n"); + return -1; + } + + return 0; +} diff --git a/src/include/cbfs_core.h b/src/include/cbfs_core.h index 32f2670..9a21a78 100644 --- a/src/include/cbfs_core.h +++ b/src/include/cbfs_core.h @@ -84,6 +84,9 @@ #define CBFS_HEADER_MAGIC 0x4F524243 #if CONFIG_ARCH_X86 #define CBFS_HEADPTR_ADDR 0xFFFFFFFC +#elif CONFIG_ARCH_ARMV7 +/* FIXME: This could also be 0xFFFF0000 with HIVECS enabled */ +#define CBFS_HEADPTR_ADDR 0x0000000C #endif #define VERSION1 0x31313131 #define VERSION2 0x31313132 diff --git a/src/include/compiler.h b/src/include/compiler.h new file mode 100644 index 0000000..39ed285 --- /dev/null +++ b/src/include/compiler.h @@ -0,0 +1,140 @@ +/* + * Keep all the ugly #ifdef for system stuff here + */ + +#ifndef __COMPILER_H__ +#define __COMPILER_H__ + +#include <stddef.h> + +#ifdef USE_HOSTCC + +#if defined(__BEOS__) || \ + defined(__NetBSD__) || \ + defined(__FreeBSD__) || \ + defined(__sun__) || \ + defined(__APPLE__) +# include <inttypes.h> +#elif defined(__linux__) || defined(__WIN32__) || defined(__MINGW32__) +# include <stdint.h> +#endif + +#include <errno.h> +#include <stdlib.h> +#include <stdint.h> +#include <stdio.h> +#include <string.h> + +#if !defined(__WIN32__) && !defined(__MINGW32__) +# include <sys/mman.h> +#endif + +/* Not all systems (like Windows) has this define, and yes + * we do replace/emulate mmap() on those systems ... + */ +#ifndef MAP_FAILED +# define MAP_FAILED ((void *)-1) +#endif + +#include <fcntl.h> +#ifndef O_BINARY /* should be define'd on __WIN32__ */ +#define O_BINARY 0 +#endif + +#ifdef __linux__ +# include <endian.h> +# include <byteswap.h> +#elif defined(__MACH__) || defined(__FreeBSD__) +# include <machine/endian.h> +typedef unsigned long ulong; +#endif + +typedef uint8_t __u8; +typedef uint16_t __u16; +typedef uint32_t __u32; +typedef unsigned int uint; + +#define uswap_16(x) \ + ((((x) & 0xff00) >> 8) | \ + (((x) & 0x00ff) << 8)) +#define uswap_32(x) \ + ((((x) & 0xff000000) >> 24) | \ + (((x) & 0x00ff0000) >> 8) | \ + (((x) & 0x0000ff00) << 8) | \ + (((x) & 0x000000ff) << 24)) +#define _uswap_64(x, sfx) \ + ((((x) & 0xff00000000000000##sfx) >> 56) | \ + (((x) & 0x00ff000000000000##sfx) >> 40) | \ + (((x) & 0x0000ff0000000000##sfx) >> 24) | \ + (((x) & 0x000000ff00000000##sfx) >> 8) | \ + (((x) & 0x00000000ff000000##sfx) << 8) | \ + (((x) & 0x0000000000ff0000##sfx) << 24) | \ + (((x) & 0x000000000000ff00##sfx) << 40) | \ + (((x) & 0x00000000000000ff##sfx) << 56)) +#if defined(__GNUC__) +# define uswap_64(x) _uswap_64(x, ull) +#else +# define uswap_64(x) _uswap_64(x, ) +#endif + +#if __BYTE_ORDER == __LITTLE_ENDIAN +# define cpu_to_le16(x) (x) +# define cpu_to_le32(x) (x) +# define cpu_to_le64(x) (x) +# define le16_to_cpu(x) (x) +# define le32_to_cpu(x) (x) +# define le64_to_cpu(x) (x) +# define cpu_to_be16(x) uswap_16(x) +# define cpu_to_be32(x) uswap_32(x) +# define cpu_to_be64(x) uswap_64(x) +# define be16_to_cpu(x) uswap_16(x) +# define be32_to_cpu(x) uswap_32(x) +# define be64_to_cpu(x) uswap_64(x) +#else +# define cpu_to_le16(x) uswap_16(x) +# define cpu_to_le32(x) uswap_32(x) +# define cpu_to_le64(x) uswap_64(x) +# define le16_to_cpu(x) uswap_16(x) +# define le32_to_cpu(x) uswap_32(x) +# define le64_to_cpu(x) uswap_64(x) +# define cpu_to_be16(x) (x) +# define cpu_to_be32(x) (x) +# define cpu_to_be64(x) (x) +# define be16_to_cpu(x) (x) +# define be32_to_cpu(x) (x) +# define be64_to_cpu(x) (x) +#endif + +#else /* !USE_HOSTCC */ + +//#include <linux/string.h> +//#include <linux/types.h> +//#include <asm/byteorder.h> +//#include <arch/byteorder.h> + +#if __SIZEOF_LONG__ == 8 +# define __WORDSIZE 64 +#elif __SIZEOF_LONG__ == 4 +# define __WORDSIZE 32 +#else +/* + * Assume 32-bit for now - only newer toolchains support this feature and + * this is only required for sandbox support at present. + */ +#define __WORDSIZE 32 +#endif + +#if 0 +/* Type for `void *' pointers. */ +typedef unsigned long int uintptr_t; +#endif + +#endif /* USE_HOSTCC */ + +/* compiler options */ +#define uninitialized_var(x) x = x + +#define likely(x) __builtin_expect(!!(x), 1) +#define unlikely(x) __builtin_expect(!!(x), 0) + +#endif diff --git a/src/include/cpu/samsung/exynos-common/adc.h b/src/include/cpu/samsung/exynos-common/adc.h new file mode 100644 index 0000000..dc905d1 --- /dev/null +++ b/src/include/cpu/samsung/exynos-common/adc.h @@ -0,0 +1,42 @@ +/* + * Copyright (C) 2010 Samsung Electronics + * Minkyu Kang mk7.kang@samsung.com + * MyungJoo Ham myungjoo.ham@samsung.com + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +#ifndef __ASM_ARM_ARCH_COMMON_ADC_H_ +#define __ASM_ARM_ARCH_COMMON_ADC_H_ + +#ifndef __ASSEMBLY__ +struct s5p_adc { + unsigned int adccon; + unsigned int adctsc; + unsigned int adcdly; + unsigned int adcdat0; + unsigned int adcdat1; + unsigned int adcupdn; + unsigned int adcclrint; + unsigned int adcmux; + unsigned int adcclrintpndnup; +}; +#endif + +#endif /* __ASM_ARM_ARCH_COMMON_ADC_H_ */ diff --git a/src/include/cpu/samsung/exynos-common/clk.h b/src/include/cpu/samsung/exynos-common/clk.h new file mode 100644 index 0000000..c978e17 --- /dev/null +++ b/src/include/cpu/samsung/exynos-common/clk.h @@ -0,0 +1,70 @@ +/* + * (C) Copyright 2012 The Chromium Authors + * (C) Copyright 2010 Samsung Electronics + * Minkyu Kang mk7.kang@samsung.com + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + */ + +#ifndef __EXYNOS_COMMON_CLK_H_ +#define __EXYNOS_COMMON_CLK_H_ + +#include <types.h> + +enum periph_id; + +#define APLL 0 +#define MPLL 1 +#define EPLL 2 +#define HPLL 3 +#define VPLL 4 +#define BPLL 5 + +enum pll_src_bit { + SRC_MPLL = 6, + SRC_EPLL, + SRC_VPLL, +}; + +/* * + * This structure is to store the src bit, div bit and prediv bit + * positions of the peripheral clocks of the src and div registers + */ +struct clk_bit_info { + s8 src_bit; /* offset in register to clock source field */ + s8 n_src_bits; /* number of bits in 'src_bit' field */ + s8 div_bit; + s8 prediv_bit; +}; + +/* FIXME(dhendrix) conflicts with stp-common/clk.h */ +#if 0 +unsigned long get_pll_clk(int pllreg); +unsigned long get_arm_clk(void); +void set_mmc_clk(int dev_index, unsigned int div); +#endif + +/** + * get the clk frequency of the required peripherial + * + * @param peripherial Peripherial id + * + * @return frequency of the peripherial clk + */ +unsigned long clock_get_periph_rate(enum periph_id peripheral); + +#endif diff --git a/src/include/cpu/samsung/exynos-common/cpu.h b/src/include/cpu/samsung/exynos-common/cpu.h new file mode 100644 index 0000000..e68de86 --- /dev/null +++ b/src/include/cpu/samsung/exynos-common/cpu.h @@ -0,0 +1,99 @@ +/* + * (C) Copyright 2010 Samsung Electronics + * Minkyu Kang mk7.kang@samsung.com + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + */ + +#ifndef _EXYNOS_COMMON_CPU_H +#define _EXYNOS_COMMON_CPU_H + +#include <cpu/samsung/s5p-common/cpu.h> + +#define DEVICE_NOT_AVAILABLE 0 + +#define EXYNOS_PRO_ID 0x10000000 + +/* Address of address of function that copys data from SD or MMC */ +#define EXYNOS_COPY_MMC_FNPTR_ADDR 0x02020030 + +/* Address of address of function that copys data from SPI */ +#define EXYNOS_COPY_SPI_FNPTR_ADDR 0x02020058 + +/* Address of address of function that copys data through USB */ +#define EXYNOS_COPY_USB_FNPTR_ADDR 0x02020070 + +/* Boot mode values */ +#define EXYNOS_USB_SECONDARY_BOOT 0xfeed0002 + +#define EXYNOS_IRAM_SECONDARY_BASE 0x02020018 + +#define EXYNOS_I2C_SPACING 0x10000 + +enum boot_mode { + /* + * Assign the OM pin values for respective boot modes. + * Exynos4 does not support spi boot and the mmc boot OM + * pin values are the same across Exynos4 and Exynos5. + */ + BOOT_MODE_MMC = 4, + BOOT_MODE_SERIAL = 20, + /* Boot based on Operating Mode pin settings */ + BOOT_MODE_OM = 32, + BOOT_MODE_USB, /* Boot using USB download */ +}; + +#if 0 +/** + * Get the U-boot size for SPL copy functions + * + * @return size of U-Boot code/data that needs to be loaded by the SPL stage + */ +unsigned int exynos_get_uboot_size(void); +#endif + +/** + * Get the boot device containing BL1, BL2 (SPL) and U-boot + * + * @return boot device + */ +enum boot_mode exynos_get_boot_device(void); + +/** + * Check if a wakeup is permitted. + * + * On some boards we need to look at a special GPIO to ensure that the wakeup + * from sleep was valid. If the wakeup is not valid we need to go through a + * full reset. + * + * The default implementation of this function allows all wakeups. + * + * @return 1 if wakeup is permitted; 0 otherwise + */ +int board_wakeup_permitted(void); + +#define cpu_is_exynos4() (s5p_get_cpu_id() == 0xc210) +#define cpu_is_exynos5() (s5p_get_cpu_id() == 0xc520) + +/** + * Init subsystems according to the reset status + * + * @return 0 for a normal boot, non-zero for a resume + */ +int lowlevel_init_subsystems(void); + +#endif /* _EXYNOS_COMMON_CPU_H */ diff --git a/src/include/cpu/samsung/exynos-common/exynos5-common.h b/src/include/cpu/samsung/exynos-common/exynos5-common.h new file mode 100644 index 0000000..5bbc52b --- /dev/null +++ b/src/include/cpu/samsung/exynos-common/exynos5-common.h @@ -0,0 +1,224 @@ +/* + * Copyright (C) 2012 Samsung Electronics + * + * Common configuration settings for EXYNOS5 based boards. + * + * 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 + */ + +/* TODO(dhendrix): some #defines are commented out here and moved to Kconfig */ + +#ifndef __EXYNOS5_CONFIG_H +#define __EXYNOS5_CONFIG_H + +/* High Level Configuration Options */ +#define CONFIG_SAMSUNG /* in a SAMSUNG core */ +#define CONFIG_S5P /* S5P Family */ +#define CONFIG_EXYNOS5 /* which is in a Exynos5 Family */ +#define BUILD_PART_FS_STUFF 1 /* Disk Partition Support */ + +#define CONFIG_ARCH_CPU_INIT /* Used to check cpu type */ + +#include <cpu/samsung/exynos5250/cpu.h> /* get chip and board defs */ + +/* Align LCD to 1MB boundary */ +#define CONFIG_LCD_ALIGNMENT MMU_SECTION_SIZE + +#define CONFIG_DISPLAY_CPUINFO +#define CONFIG_DISPLAY_BOARDINFO_LATE +#define CONFIG_SYS_CONSOLE_INFO_QUIET +#define CONFIG_BOARD_LATE_INIT + +#define CONFIG_CMD_SHA256 +//#define CONFIG_EXYNOS_ACE_SHA + +//#define CONFIG_SYS_SDRAM_BASE 0x40000000 +//#define CONFIG_SYS_TEXT_BASE 0x43e00000 + +#define CONFIG_SETUP_MEMORY_TAGS +#define CONFIG_CMDLINE_TAG +#define CONFIG_INITRD_TAG +#define CONFIG_CMDLINE_EDITING + +/* Power Down Modes */ +#define S5P_CHECK_SLEEP 0x00000BAD +#define S5P_CHECK_DIDLE 0xBAD00000 +#define S5P_CHECK_LPA 0xABAD0000 + +/* Offset for inform registers */ +#define INFORM0_OFFSET 0x800 +#define INFORM1_OFFSET 0x804 + +/* Size of malloc() pool */ +#define CONFIG_SYS_MALLOC_LEN (CONFIG_ENV_SIZE + (4 << 20)) + +/* select serial console configuration */ +#define CONFIG_SERIAL_MULTI +//#define CONFIG_BAUDRATE 115200 +#define EXYNOS5_DEFAULT_UART_OFFSET 0x010000 + +#define CONFIG_BOARD_EARLY_INIT_F + +/* PWM */ +#define CONFIG_PWM + +/* allow to overwrite serial and ethaddr */ +#define CONFIG_ENV_OVERWRITE + +/* SPL */ +#define CONFIG_SPL +#define CONFIG_SPL_GPIO_SUPPORT +#define CONFIG_SPL_POWER_SUPPORT +#define CONFIG_SPL_I2C_SUPPORT +#define CONFIG_SPL_SERIAL_SUPPORT +#define CONFIG_SPL_LIBCOMMON_SUPPORT + +/* Number of GPIOS to use for board revision detection */ +#define CONFIG_BOARD_REV_GPIO_COUNT 2 + +/* Miscellaneous configurable options */ +#define CONFIG_SYS_LONGHELP /* undef to save memory */ +#define CONFIG_SYS_HUSH_PARSER /* use "hush" command parser */ +#define CONFIG_SYS_PROMPT_HUSH_PS2 "> " +#define CONFIG_SYS_CBSIZE 256 /* Console I/O Buffer Size */ +#define CONFIG_SYS_PBSIZE 384 /* Print Buffer Size */ +#define CONFIG_SYS_MAXARGS 16 /* max number of command args */ +/* Boot Argument Buffer Size */ +#define CONFIG_SYS_BARGSIZE CONFIG_SYS_CBSIZE +/* memtest works on */ +#define CONFIG_SYS_MEMTEST_START CONFIG_SYS_SDRAM_BASE +#define CONFIG_SYS_MEMTEST_END (CONFIG_SYS_SDRAM_BASE + 0x5E00000) +#define CONFIG_SYS_LOAD_ADDR (CONFIG_SYS_SDRAM_BASE + 0x3E00000) + +#define CONFIG_SYS_HZ 1000 + +/* valid baudrates */ +#define CONFIG_SYS_BAUDRATE_TABLE { 9600, 19200, 38400, 57600, 115200 } + +/* Stack sizes */ +#define CONFIG_STACKSIZE (256 << 10) /* 256KB */ + +#define CONFIG_SYS_MONITOR_BASE 0x00000000 + +#ifdef CONFIG_SPI_FLASH +/* Enable SPI H/W Controller Driver support */ +#define CONFIG_EXYNOS_SPI + +/* FIXME(dhendrix): We should be concerned with SPI flash parts here... */ +#if 0 +#define CONFIG_CMD_SF +#define CONFIG_CMD_SPI +#define CONFIG_SPI_FLASH_WINBOND +/* Enable Gigadevice SPI flash support for Snow board */ +#define CONFIG_SPI_FLASH_GIGADEVICE +#define CONFIG_SF_DEFAULT_MODE SPI_MODE_0 +/* Set speed for SPI flash */ +#define CONFIG_SF_DEFAULT_SPEED 50000000 +#endif +#endif + +/* FLASH and environment organization */ +#define CONFIG_SYS_NO_FLASH +#undef CONFIG_CMD_IMLS + +#define CONFIG_SECURE_BL1_ONLY + +/* Secure FW size configuration */ +#ifdef CONFIG_SECURE_BL1_ONLY +#define CONFIG_SEC_FW_SIZE (8 << 10) /* 8KB */ +#else +#define CONFIG_SEC_FW_SIZE 0 +#endif + +/* Configuration of BL1, BL2, ENV Blocks on mmc */ +#define CONFIG_RES_BLOCK_SIZE (512) +#define CONFIG_BL1_SIZE (16 << 10) /*16 K reserved for BL1*/ +#define CONFIG_BL2_SIZE (512UL << 10UL) /* 512 KB */ +#define CONFIG_ENV_SIZE (16 << 10) /* 16 KB */ + +#define CONFIG_BL1_OFFSET (CONFIG_RES_BLOCK_SIZE + CONFIG_SEC_FW_SIZE) +#define CONFIG_BL2_OFFSET (CONFIG_BL1_OFFSET + CONFIG_BL1_SIZE) + +#define SPI_FLASH_UBOOT_POS (CONFIG_SEC_FW_SIZE + CONFIG_BL1_SIZE) + +#ifdef CONFIG_ENV_IS_IN_SPI_FLASH +#define CONFIG_ENV_SPI_MODE SPI_MODE_0 +#define CONFIG_ENV_OFFSET (CONFIG_SEC_FW_SIZE + CONFIG_BL1_SIZE + \ + CONFIG_BL2_SIZE) +#define CONFIG_ENV_SECT_SIZE CONFIG_ENV_SIZE +#define CONFIG_ENV_SPI_BUS 1 +#else /* CONFIG_ENV_IS_IN_MMC */ +#define CONFIG_ENV_OFFSET (CONFIG_BL2_OFFSET + CONFIG_BL2_SIZE) +#endif + +/* U-boot copy size from boot Media to DRAM.*/ +#define BL2_START_OFFSET (CONFIG_BL2_OFFSET/512) + +/* Set the emmc bus width to 8 */ +#define CONFIG_MSHCI_BUS_WIDTH 8 +#define CONFIG_MSHCI_PERIPH_ID PERIPH_ID_SDMMC0 + +#if BUILD_PART_FS_STUFF +#define CONFIG_DOS_PARTITION +#define CONFIG_EFI_PARTITION +#endif + +#if 0 +/* + * FIXME(dhendrix): 0x02050000 was in the u-boot sources, but the docs say the + * iRAM range is 0x0202_0000 - 0x0207_7fff (352KB). + */ +#define CONFIG_IRAM_TOP 0x02050000 + +/* + * Put the initial stack pointer 1KB below this to allow room for the + * SPL marker. This value is arbitrary, but gd_t is placed starting here. + */ +#define CONFIG_SYS_INIT_SP_ADDR (CONFIG_IRAM_TOP - 0x800) +#endif + +/* The place where we put our SPL marker */ +#define CONFIG_SPL_MARKER (CONFIG_IRAM_TOP - 4) + +/* Place to stash bootstage data from first-stage U-Boot */ +#define CONFIG_BOOTSTAGE_STASH (CONFIG_IRAM_TOP - 0x400) +#define CONFIG_BOOTSTAGE_STASH_SIZE 0x3fc + +/* The top of the SPL stack, also used for early U-Boot init */ +//#define CONFIG_IRAM_STACK CONFIG_SYS_INIT_SP_ADDR + +//#define CONFIG_SPL_LDSCRIPT +//#define CONFIG_SPL_TEXT_BASE 0x02023400 +//#define CONFIG_SPL_MAX_SIZE (14 * 1024) + +/* Enable devicetree support */ +#define CONFIG_OF_LIBFDT + +#define CONFIG_SYS_THUMB_BUILD + +/* We spend about 100us getting from reset to SPL */ +#define CONFIG_SPL_TIME_US 100000 + +/* Stringify a token */ +#ifndef STRINGIFY +#define _STRINGIFY(x) #x +#define STRINGIFY(x) _STRINGIFY(x) +#endif + +#endif /* __EXYNOS5_CONFIG_H */ diff --git a/src/include/cpu/samsung/exynos-common/gpio.h b/src/include/cpu/samsung/exynos-common/gpio.h new file mode 100644 index 0000000..37dd678 --- /dev/null +++ b/src/include/cpu/samsung/exynos-common/gpio.h @@ -0,0 +1,73 @@ +/* + * (C) Copyright 2010 Samsung Electronics + * Minkyu Kang mk7.kang@samsung.com + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +#ifndef __ASM_ARCH_COMMON_GPIO_H +#define __ASM_ARCH_COMMON_GPIO_H + +#ifndef __ASSEMBLY__ /* FIXME: not needed (i hope)? */ +#include <cpu/samsung/s5p-common/gpio.h> +/* FIXME: s5p's gpio.h and exynos' gpio.h have a lot of conflicting + definitions */ +#if 0 +struct s5p_gpio_bank { + unsigned int con; + unsigned int dat; + unsigned int pull; + unsigned int drv; + unsigned int pdn_con; + unsigned int pdn_pull; + unsigned char res1[8]; +}; + +/* functions */ +void s5p_gpio_cfg_pin(struct s5p_gpio_bank *bank, int gpio, int cfg); +void s5p_gpio_direction_output(struct s5p_gpio_bank *bank, int gpio, int en); +void s5p_gpio_direction_input(struct s5p_gpio_bank *bank, int gpio); +void s5p_gpio_set_value(struct s5p_gpio_bank *bank, int gpio, int en); +unsigned int s5p_gpio_get_value(struct s5p_gpio_bank *bank, int gpio); +void s5p_gpio_set_pull(struct s5p_gpio_bank *bank, int gpio, int mode); +void s5p_gpio_set_drv(struct s5p_gpio_bank *bank, int gpio, int mode); +void s5p_gpio_set_rate(struct s5p_gpio_bank *bank, int gpio, int mode); +#endif + +/* GPIO pins per bank */ +#define GPIO_PER_BANK 8 + +#endif + +/* Pin configurations */ +#define EXYNOS_GPIO_INPUT 0x0 +#define EXYNOS_GPIO_OUTPUT 0x1 +#define EXYNOS_GPIO_IRQ 0xf +#define EXYNOS_GPIO_FUNC(x) (x) + +/* Pull mode */ +#define EXYNOS_GPIO_PULL_NONE 0x0 +#define EXYNOS_GPIO_PULL_DOWN 0x1 +#define EXYNOS_GPIO_PULL_UP 0x3 + +/* Drive Strength level */ +#define EXYNOS_GPIO_DRV_1X 0x0 +#define EXYNOS_GPIO_DRV_3X 0x1 +#define EXYNOS_GPIO_DRV_2X 0x2 +#define EXYNOS_GPIO_DRV_4X 0x3 +#define EXYNOS_GPIO_DRV_FAST 0x0 +#define EXYNOS_GPIO_DRV_SLOW 0x1 +#endif diff --git a/src/include/cpu/samsung/exynos-common/mmc.h b/src/include/cpu/samsung/exynos-common/mmc.h new file mode 100644 index 0000000..4e43589 --- /dev/null +++ b/src/include/cpu/samsung/exynos-common/mmc.h @@ -0,0 +1,77 @@ +/* + * (C) Copyright 2009 SAMSUNG Electronics + * Minkyu Kang mk7.kang@samsung.com + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#ifndef __ASM_ARCH_COMMON_MMC_H_ +#define __ASM_ARCH_COMMON_MMC_H_ + +#ifndef __ASSEMBLY__ +struct s5p_mmc { + unsigned int sysad; + unsigned short blksize; + unsigned short blkcnt; + unsigned int argument; + unsigned short trnmod; + unsigned short cmdreg; + unsigned int rspreg0; + unsigned int rspreg1; + unsigned int rspreg2; + unsigned int rspreg3; + unsigned int bdata; + unsigned int prnsts; + unsigned char hostctl; + unsigned char pwrcon; + unsigned char blkgap; + unsigned char wakcon; + unsigned short clkcon; + unsigned char timeoutcon; + unsigned char swrst; + unsigned int norintsts; /* errintsts */ + unsigned int norintstsen; /* errintstsen */ + unsigned int norintsigen; /* errintsigen */ + unsigned short acmd12errsts; + unsigned char res1[2]; + unsigned int capareg; + unsigned char res2[4]; + unsigned int maxcurr; + unsigned char res3[0x34]; + unsigned int control2; + unsigned int control3; + unsigned char res4[4]; + unsigned int control4; + unsigned char res5[0x6e]; + unsigned short hcver; + unsigned char res6[0xFF00]; +}; + +struct mmc_host { + struct s5p_mmc *reg; + unsigned int version; /* SDHCI spec. version */ + unsigned int clock; /* Current clock (MHz) */ + int dev_index; +}; + +#ifdef CONFIG_OF_CONTROL +int s5p_mmc_init(const void *blob); +#else +int s5p_mmc_init(int dev_index, int bus_width); +#endif + +#endif /* __ASSEMBLY__ */ +#endif diff --git a/src/include/cpu/samsung/exynos-common/mshc.h b/src/include/cpu/samsung/exynos-common/mshc.h new file mode 100644 index 0000000..bdb0a9c --- /dev/null +++ b/src/include/cpu/samsung/exynos-common/mshc.h @@ -0,0 +1,170 @@ +/* + * (C) Copyright 2012 SAMSUNG Electronics + * Abhilash Kesavan a.kesavan@samsung.com + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ +#ifndef __ASM_ARCH_COMMON_MSHC_H +#define __ASM_ARCH_COMMON_MSHC_H + +#include <asm/arch/pinmux.h> +#ifndef __ASSEMBLY__ +struct mshci_host { + struct s5p_mshci *reg; /* Mapped address */ + unsigned int clock; /* Current clock in MHz */ + enum periph_id peripheral; +}; + +struct s5p_mshci { + unsigned int ctrl; + unsigned int pwren; + unsigned int clkdiv; + unsigned int clksrc; + unsigned int clkena; + unsigned int tmout; + unsigned int ctype; + unsigned int blksiz; + unsigned int bytcnt; + unsigned int intmask; + unsigned int cmdarg; + unsigned int cmd; + unsigned int resp0; + unsigned int resp1; + unsigned int resp2; + unsigned int resp3; + unsigned int mintsts; + unsigned int rintsts; + unsigned int status; + unsigned int fifoth; + unsigned int cdetect; + unsigned int wrtprt; + unsigned int gpio; + unsigned int tcbcnt; + unsigned int tbbcnt; + unsigned int debnce; + unsigned int usrid; + unsigned int verid; + unsigned int hcon; + unsigned int uhs_reg; + unsigned int rst_n; + unsigned char reserved1[4]; + unsigned int bmod; + unsigned int pldmnd; + unsigned int dbaddr; + unsigned int idsts; + unsigned int idinten; + unsigned int dscaddr; + unsigned int bufaddr; + unsigned int clksel; + unsigned char reserved2[460]; + unsigned int cardthrctl; +}; + +/* + * Struct idma + * Holds the descriptor list + */ +struct mshci_idmac { + u32 des0; + u32 des1; + u32 des2; + u32 des3; +}; + +/* Control Register Register */ +#define CTRL_RESET (0x1 << 0) +#define FIFO_RESET (0x1 << 1) +#define DMA_RESET (0x1 << 2) +#define DMA_ENABLE (0x1 << 5) +#define SEND_AS_CCSD (0x1 << 10) +#define ENABLE_IDMAC (0x1 << 25) + +/* Power Enable Register */ +#define POWER_ENABLE (0x1 << 0) + +/* Clock Enable Register */ +#define CLK_ENABLE (0x1 << 0) +#define CLK_DISABLE (0x0 << 0) + +/* Timeout Register */ +#define TMOUT_MAX 0xffffffff + +/* Card Type Register */ +#define PORT0_CARD_WIDTH1 0 +#define PORT0_CARD_WIDTH4 (0x1 << 0) +#define PORT0_CARD_WIDTH8 (0x1 << 16) + +/* Interrupt Mask Register */ +#define INTMSK_ALL 0xffffffff +#define INTMSK_RE (0x1 << 1) +#define INTMSK_CDONE (0x1 << 2) +#define INTMSK_DTO (0x1 << 3) +#define INTMSK_DCRC (0x1 << 7) +#define INTMSK_RTO (0x1 << 8) +#define INTMSK_DRTO (0x1 << 9) +#define INTMSK_HTO (0x1 << 10) +#define INTMSK_FRUN (0x1 << 11) +#define INTMSK_HLE (0x1 << 12) +#define INTMSK_SBE (0x1 << 13) +#define INTMSK_ACD (0x1 << 14) +#define INTMSK_EBE (0x1 << 15) + +/* Command Register */ +#define CMD_RESP_EXP_BIT (0x1 << 6) +#define CMD_RESP_LENGTH_BIT (0x1 << 7) +#define CMD_CHECK_CRC_BIT (0x1 << 8) +#define CMD_DATA_EXP_BIT (0x1 << 9) +#define CMD_RW_BIT (0x1 << 10) +#define CMD_SENT_AUTO_STOP_BIT (0x1 << 12) +#define CMD_WAIT_PRV_DAT_BIT (0x1 << 13) +#define CMD_SEND_CLK_ONLY (0x1 << 21) +#define CMD_USE_HOLD_REG (0x1 << 29) +#define CMD_STRT_BIT (0x1 << 31) +#define CMD_ONLY_CLK (CMD_STRT_BIT | CMD_SEND_CLK_ONLY | \ + CMD_WAIT_PRV_DAT_BIT) + +/* Raw Interrupt Register */ +#define DATA_ERR (INTMSK_EBE | INTMSK_SBE | INTMSK_HLE | \ + INTMSK_FRUN | INTMSK_EBE | INTMSK_DCRC) +#define DATA_TOUT (INTMSK_HTO | INTMSK_DRTO) + +/* Status Register */ +#define DATA_BUSY (0x1 << 9) + +/* FIFO Threshold Watermark Register */ +#define TX_WMARK (0xFFF << 0) +#define RX_WMARK (0xFFF << 16) +#define MSIZE_MASK (0x7 << 28) + +/* DW DMA Mutiple Transaction Size */ +#define MSIZE_8 (2 << 28) + +/* Bus Mode Register */ +#define BMOD_IDMAC_RESET (0x1 << 0) +#define BMOD_IDMAC_FB (0x1 << 1) +#define BMOD_IDMAC_ENABLE (0x1 << 7) + +/* IDMAC bits */ +#define MSHCI_IDMAC_OWN (0x1 << 31) +#define MSHCI_IDMAC_CH (0x1 << 4) +#define MSHCI_IDMAC_FS (0x1 << 3) +#define MSHCI_IDMAC_LD (0x1 << 2) + +int s5p_mshci_init(const void *blob); + +#endif +#endif + diff --git a/src/include/cpu/samsung/exynos-common/pwm.h b/src/include/cpu/samsung/exynos-common/pwm.h new file mode 100644 index 0000000..e35d88d --- /dev/null +++ b/src/include/cpu/samsung/exynos-common/pwm.h @@ -0,0 +1,68 @@ +/* + * Copyright (C) 2009 Samsung Electronics + * Kyungmin Park kyungmin.park@samsung.com + * Minkyu Kang mk7.kang@samsung.com + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +#ifndef __ASM_ARM_ARCH_COMMON_PWM_H_ +#define __ASM_ARM_ARCH_COMMON_PWM_H_ + +#define PRESCALER_0 (8 - 1) /* prescaler of timer 0, 1 */ +#define PRESCALER_1 (16 - 1) /* prescaler of timer 2, 3, 4 */ + +/* Divider MUX */ +#define MUX_DIV_1 0 /* 1/1 period */ +#define MUX_DIV_2 1 /* 1/2 period */ +#define MUX_DIV_4 2 /* 1/4 period */ +#define MUX_DIV_8 3 /* 1/8 period */ +#define MUX_DIV_16 4 /* 1/16 period */ + +#define MUX_DIV_SHIFT(x) (x * 4) + +#define TCON_OFFSET(x) ((x + 1) * (!!x) << 2) + +#define TCON_START(x) (1 << TCON_OFFSET(x)) +#define TCON_UPDATE(x) (1 << (TCON_OFFSET(x) + 1)) +#define TCON_INVERTER(x) (1 << (TCON_OFFSET(x) + 2)) +#define TCON_AUTO_RELOAD(x) (1 << (TCON_OFFSET(x) + 3)) +#define TCON4_AUTO_RELOAD (1 << 22) + +#ifndef __ASSEMBLY__ +struct s5p_timer { + unsigned int tcfg0; + unsigned int tcfg1; + unsigned int tcon; + unsigned int tcntb0; + unsigned int tcmpb0; + unsigned int tcnto0; + unsigned int tcntb1; + unsigned int tcmpb1; + unsigned int tcnto1; + unsigned int tcntb2; + unsigned int tcmpb2; + unsigned int tcnto2; + unsigned int tcntb3; + unsigned int tcmpb3; + unsigned int tcnto3; + unsigned int tcntb4; + unsigned int tcnto4; + unsigned int tintcstat; +}; +#endif /* __ASSEMBLY__ */ + +#endif diff --git a/src/include/cpu/samsung/exynos-common/spi.h b/src/include/cpu/samsung/exynos-common/spi.h new file mode 100644 index 0000000..3430ac1 --- /dev/null +++ b/src/include/cpu/samsung/exynos-common/spi.h @@ -0,0 +1,89 @@ +/* + * (C) Copyright 2012 SAMSUNG Electronics + * Padmavathi Venna padma.v@samsung.com + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef __ASM_ARCH_EXYNOS_COMMON_SPI_H_ +#define __ASM_ARCH_EXYNOS_COMMON_SPI_H_ + +#ifndef __ASSEMBLY__ + +/* SPI peripheral register map; padded to 64KB */ +struct exynos_spi { + unsigned int ch_cfg; /* 0x00 */ + unsigned char reserved0[4]; + unsigned int mode_cfg; /* 0x08 */ + unsigned int cs_reg; /* 0x0c */ + unsigned char reserved1[4]; + unsigned int spi_sts; /* 0x14 */ + unsigned int tx_data; /* 0x18 */ + unsigned int rx_data; /* 0x1c */ + unsigned int pkt_cnt; /* 0x20 */ + unsigned char reserved2[4]; + unsigned int swap_cfg; /* 0x28 */ + unsigned int fb_clk; /* 0x2c */ + unsigned char padding[0xffd0]; +}; + +#define EXYNOS_SPI_MAX_FREQ 50000000 + +#define SPI_TIMEOUT_MS 10 + +#define SF_READ_DATA_CMD 0x3 + +/* SPI_CHCFG */ +#define SPI_CH_HS_EN (1 << 6) +#define SPI_CH_RST (1 << 5) +#define SPI_SLAVE_MODE (1 << 4) +#define SPI_CH_CPOL_L (1 << 3) +#define SPI_CH_CPHA_B (1 << 2) +#define SPI_RX_CH_ON (1 << 1) +#define SPI_TX_CH_ON (1 << 0) + +/* SPI_MODECFG */ +#define SPI_MODE_CH_WIDTH_WORD (0x2 << 29) +#define SPI_MODE_BUS_WIDTH_WORD (0x2 << 17) + +/* SPI_CSREG */ +#define SPI_SLAVE_SIG_INACT (1 << 0) + +/* SPI_STS */ +#define SPI_ST_TX_DONE (1 << 25) +#define SPI_FIFO_LVL_MASK 0x1ff +#define SPI_TX_LVL_OFFSET 6 +#define SPI_RX_LVL_OFFSET 15 + +/* Feedback Delay */ +#define SPI_CLK_BYPASS (0 << 0) +#define SPI_FB_DELAY_90 (1 << 0) +#define SPI_FB_DELAY_180 (2 << 0) +#define SPI_FB_DELAY_270 (3 << 0) + +/* Packet Count */ +#define SPI_PACKET_CNT_EN (1 << 16) + +/* Swap config */ +#define SPI_TX_SWAP_EN (1 << 0) +#define SPI_TX_BYTE_SWAP (1 << 2) +#define SPI_TX_HWORD_SWAP (1 << 3) +#define SPI_TX_BYTE_SWAP (1 << 2) +#define SPI_RX_SWAP_EN (1 << 4) +#define SPI_RX_BYTE_SWAP (1 << 6) +#define SPI_RX_HWORD_SWAP (1 << 7) + +#endif /* __ASSEMBLY__ */ +#endif diff --git a/src/include/cpu/samsung/exynos-common/spl.h b/src/include/cpu/samsung/exynos-common/spl.h new file mode 100644 index 0000000..1df4aed --- /dev/null +++ b/src/include/cpu/samsung/exynos-common/spl.h @@ -0,0 +1,94 @@ +/* + * Copyright (c) 2012 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 + */ + +#ifndef __ASM_ARCH_EXYNOS_SPL_H__ +#define __ASM_ARCH_EXYNOS_SPL_H__ + +#include <cpu/samsung/exynos-common/cpu.h> +/* FIXME(dhendrix): non-common header included by a common header... */ +#include <cpu/samsung/exynos5250/dmc.h> + +/* Parameters of early board initialization in SPL */ +struct spl_machine_param { + /* Add fields as and when required */ + u32 signature; + u32 version; /* Version number */ + u32 size; /* Size of block */ + /** + * Parameters we expect, in order, terminated with \0. Each parameter + * is a single character representing one 32-bit word in this + * structure. + * + * Valid characters in this string are: + * + * Code Name + * v mem_iv_size + * m mem_type + * u uboot_size + * b boot_source + * f frequency_mhz (memory frequency in MHz) + * a ARM clock frequency in MHz + * s serial base address + * i i2c base address for early access (meant for PMIC) + * r board rev GPIO numbers used to read board revision + * (lower halfword=bit 0, upper=bit 1) + * M Memory Manufacturer name + * w Bad Wake GPIO number + * \0 termination + */ + char params[12]; /* Length must be word-aligned */ + u32 mem_iv_size; /* Memory channel interleaving size */ + enum ddr_mode mem_type; /* Type of on-board memory */ + /* + * U-boot size - The iROM mmc copy function used by the SPL takes a + * block count paramter to describe the u-boot size unlike the spi + * boot copy function which just uses the u-boot size directly. Align + * the u-boot size to block size (512 bytes) when populating the SPL + * table only for mmc boot. + */ + u32 uboot_size; + enum boot_mode boot_source; /* Boot device */ + unsigned frequency_mhz; /* Frequency of memory in MHz */ + unsigned arm_freq_mhz; /* ARM Frequency in MHz */ + u32 serial_base; /* Serial base address */ + u32 i2c_base; /* i2c base address */ + u32 board_rev_gpios; /* Board revision GPIOs */ + enum mem_manuf mem_manuf; /* Memory Manufacturer */ + u32 bad_wake_gpio; /* If high at wake time disallow wake */ +} __attribute__((__packed__)); + +/** + * Validate signature and return a pointer to the parameter table. If the + * signature is invalid, call panic() and never return. + * + * @return pointer to the parameter table if signature matched or never return. + */ +struct spl_machine_param *spl_get_machine_params(void); + +/* + * Initialize the timer and serial driver in SPL u-boot. + * Besides the serial driver, it also setup the minimal set of its dependency, + * like gd struct, pinmux, and serial. + */ +void spl_early_init(void); + +#endif /* __ASM_ARCH_EXYNOS_SPL_H__ */ diff --git a/src/include/cpu/samsung/exynos-common/sromc.h b/src/include/cpu/samsung/exynos-common/sromc.h new file mode 100644 index 0000000..b413373 --- /dev/null +++ b/src/include/cpu/samsung/exynos-common/sromc.h @@ -0,0 +1,69 @@ +/* + * (C) Copyright 2010 Samsung Electronics + * Naveen Krishna Ch ch.naveen@samsung.com + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + * Note: This file contains the register description for SROMC + * + */ + +#ifndef __ASM_ARCH_COMMON_SROMC_H_ +#define __ASM_ARCH_COMMON_SROMC_H_ + +#define SROMC_DATA16_WIDTH(x) (1<<((x*4)+0)) +#define SROMC_BYTE_ADDR_MODE(x) (1<<((x*4)+1)) /* 0-> Half-word base address*/ + /* 1-> Byte base address*/ +#define SROMC_WAIT_ENABLE(x) (1<<((x*4)+2)) +#define SROMC_BYTE_ENABLE(x) (1<<((x*4)+3)) + +#define SROMC_BC_TACS(x) (x << 28) /* address set-up */ +#define SROMC_BC_TCOS(x) (x << 24) /* chip selection set-up */ +#define SROMC_BC_TACC(x) (x << 16) /* access cycle */ +#define SROMC_BC_TCOH(x) (x << 12) /* chip selection hold */ +#define SROMC_BC_TAH(x) (x << 8) /* address holding time */ +#define SROMC_BC_TACP(x) (x << 4) /* page mode access cycle */ +#define SROMC_BC_PMC(x) (x << 0) /* normal(1data)page mode configuration */ + +#ifndef __ASSEMBLY__ +struct s5p_sromc { + unsigned int bw; + unsigned int bc[4]; +}; +#endif /* __ASSEMBLY__ */ + +/* Configure the Band Width and Bank Control Regs for required SROMC Bank */ +void s5p_config_sromc(u32 srom_bank, u32 srom_bw_conf, u32 srom_bc_conf); + +enum { + FDT_SROM_PMC, + FDT_SROM_TACP, + FDT_SROM_TAH, + FDT_SROM_TCOH, + FDT_SROM_TACC, + FDT_SROM_TCOS, + FDT_SROM_TACS, + + FDT_SROM_TIMING_COUNT, +}; + +struct fdt_sromc { + u8 bank; /* srom bank number */ + u8 width; /* bus width in bytes */ + unsigned int timing[FDT_SROM_TIMING_COUNT]; /* timing parameters */ +}; + +#endif /* __ASM_ARCH_COMMON_SROMC_H_ */ diff --git a/src/include/cpu/samsung/exynos-common/sys_proto.h b/src/include/cpu/samsung/exynos-common/sys_proto.h new file mode 100644 index 0000000..11f1636 --- /dev/null +++ b/src/include/cpu/samsung/exynos-common/sys_proto.h @@ -0,0 +1,32 @@ +/* + * Copyright (C) 2010 Samsung Electrnoics + * Minkyu Kang mk7.kang@samsung.com + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +#ifndef _SYS_PROTO_H_ +#define _SYS_PROTO_H_ + +u32 get_device_type(void); +void invalidate_dcache(u32); +void l2_cache_disable(void); +void l2_cache_enable(void); + +#endif diff --git a/src/include/cpu/samsung/exynos-common/uart.h b/src/include/cpu/samsung/exynos-common/uart.h new file mode 100644 index 0000000..350e224 --- /dev/null +++ b/src/include/cpu/samsung/exynos-common/uart.h @@ -0,0 +1,55 @@ +/* + * (C) Copyright 2009 Samsung Electronics + * Minkyu Kang mk7.kang@samsung.com + * Heungjun Kim riverful.kim@samsung.com + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + */ + +#ifndef __EXYNOS_COMMON_UART_H_ +#define __EXYNOS_COMMON_UART_H_ + +/* baudrate rest value */ +union br_rest { + unsigned short slot; /* udivslot */ + unsigned char value; /* ufracval */ +}; + +struct s5p_uart { + unsigned int ulcon; + unsigned int ucon; + unsigned int ufcon; + unsigned int umcon; + unsigned int utrstat; + unsigned int uerstat; + unsigned int ufstat; + unsigned int umstat; + unsigned char utxh; + unsigned char res1[3]; + unsigned char urxh; + unsigned char res2[3]; + unsigned int ubrdiv; + union br_rest rest; + unsigned char res3[0xffd0]; +}; + +static inline int s5p_uart_divslot(void) +{ + return 0; +} + +#endif diff --git a/src/include/cpu/samsung/exynos-common/watchdog.h b/src/include/cpu/samsung/exynos-common/watchdog.h new file mode 100644 index 0000000..af98638 --- /dev/null +++ b/src/include/cpu/samsung/exynos-common/watchdog.h @@ -0,0 +1,57 @@ +/* + * Copyright (C) 2011 Samsung Electronics + * Heungjun Kim riverful.kim@samsung.com + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +#ifndef __ASM_ARM_ARCH_COMMON_WATCHDOG_H_ +#define __ASM_ARM_ARCH_COMMON_WATCHDOG_H_ + +#define WTCON_RESET_OFFSET 0 +#define WTCON_INTEN_OFFSET 2 +#define WTCON_CLKSEL_OFFSET 3 +#define WTCON_EN_OFFSET 5 +#define WTCON_PRE_OFFSET 8 + +#define WTCON_CLK_16 0x0 +#define WTCON_CLK_32 0x1 +#define WTCON_CLK_64 0x2 +#define WTCON_CLK_128 0x3 + +#define WTCON_CLK(x) ((x & 0x3) << WTCON_CLKSEL_OFFSET) +#define WTCON_PRESCALER(x) ((x) << WTCON_PRE_OFFSET) +#define WTCON_EN (0x1 << WTCON_EN_OFFSET) +#define WTCON_RESET (0x1 << WTCON_RESET_OFFSET) +#define WTCON_INT (0x1 << WTCON_INTEN_OFFSET) + +#ifndef __ASSEMBLY__ +struct s5p_watchdog { + unsigned int wtcon; + unsigned int wtdat; + unsigned int wtcnt; + unsigned int wtclrint; +}; + +/* functions */ +void wdt_stop(void); +void wdt_start(unsigned int timeout); +#endif /* __ASSEMBLY__ */ + +#endif diff --git a/src/include/cpu/samsung/exynos5250/ace_sfr.h b/src/include/cpu/samsung/exynos5250/ace_sfr.h new file mode 100644 index 0000000..8f1c893 --- /dev/null +++ b/src/include/cpu/samsung/exynos5250/ace_sfr.h @@ -0,0 +1,310 @@ +/* + * Header file for Advanced Crypto Engine - SFR definitions + * + * Copyright (c) 2012 Samsung Electronics + * + * 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 __ACE_SFR_H +#define __ACE_SFR_H + +struct exynos_ace_sfr { + unsigned int fc_intstat; /* base + 0 */ + unsigned int fc_intenset; + unsigned int fc_intenclr; + unsigned int fc_intpend; + unsigned int fc_fifostat; + unsigned int fc_fifoctrl; + unsigned int fc_global; + unsigned int res1; + unsigned int fc_brdmas; + unsigned int fc_brdmal; + unsigned int fc_brdmac; + unsigned int res2; + unsigned int fc_btdmas; + unsigned int fc_btdmal; + unsigned int fc_btdmac; + unsigned int res3; + unsigned int fc_hrdmas; + unsigned int fc_hrdmal; + unsigned int fc_hrdmac; + unsigned int res4; + unsigned int fc_pkdmas; + unsigned int fc_pkdmal; + unsigned int fc_pkdmac; + unsigned int fc_pkdmao; + unsigned char res5[0x1a0]; + + unsigned int aes_control; /* base + 0x200 */ + unsigned int aes_status; + unsigned char res6[0x8]; + unsigned int aes_in[4]; + unsigned int aes_out[4]; + unsigned int aes_iv[4]; + unsigned int aes_cnt[4]; + unsigned char res7[0x30]; + unsigned int aes_key[8]; + unsigned char res8[0x60]; + + unsigned int tdes_control; /* base + 0x300 */ + unsigned int tdes_status; + unsigned char res9[0x8]; + unsigned int tdes_key[6]; + unsigned int tdes_iv[2]; + unsigned int tdes_in[2]; + unsigned int tdes_out[2]; + unsigned char res10[0xc0]; + + unsigned int hash_control; /* base + 0x400 */ + unsigned int hash_control2; + unsigned int hash_fifo_mode; + unsigned int hash_byteswap; + unsigned int hash_status; + unsigned char res11[0xc]; + unsigned int hash_msgsize_low; + unsigned int hash_msgsize_high; + unsigned int hash_prelen_low; + unsigned int hash_prelen_high; + unsigned int hash_in[16]; + unsigned int hash_key_in[16]; + unsigned int hash_iv[8]; + unsigned char res12[0x30]; + unsigned int hash_result[8]; + unsigned char res13[0x20]; + unsigned int hash_seed[8]; + unsigned int hash_prng[8]; + unsigned char res14[0x180]; + + unsigned int pka_sfr[5]; /* base + 0x700 */ +}; + +/* ACE_FC_INT */ +#define ACE_FC_PKDMA (1 << 0) +#define ACE_FC_HRDMA (1 << 1) +#define ACE_FC_BTDMA (1 << 2) +#define ACE_FC_BRDMA (1 << 3) +#define ACE_FC_PRNG_ERROR (1 << 4) +#define ACE_FC_MSG_DONE (1 << 5) +#define ACE_FC_PRNG_DONE (1 << 6) +#define ACE_FC_PARTIAL_DONE (1 << 7) + +/* ACE_FC_FIFOSTAT */ +#define ACE_FC_PKFIFO_EMPTY (1 << 0) +#define ACE_FC_PKFIFO_FULL (1 << 1) +#define ACE_FC_HRFIFO_EMPTY (1 << 2) +#define ACE_FC_HRFIFO_FULL (1 << 3) +#define ACE_FC_BTFIFO_EMPTY (1 << 4) +#define ACE_FC_BTFIFO_FULL (1 << 5) +#define ACE_FC_BRFIFO_EMPTY (1 << 6) +#define ACE_FC_BRFIFO_FULL (1 << 7) + +/* ACE_FC_FIFOCTRL */ +#define ACE_FC_SELHASH_MASK (3 << 0) +#define ACE_FC_SELHASH_EXOUT (0 << 0) /* independent source */ +#define ACE_FC_SELHASH_BCIN (1 << 0) /* blk cipher input */ +#define ACE_FC_SELHASH_BCOUT (2 << 0) /* blk cipher output */ +#define ACE_FC_SELBC_MASK (1 << 2) +#define ACE_FC_SELBC_AES (0 << 2) /* AES */ +#define ACE_FC_SELBC_DES (1 << 2) /* DES */ + +/* ACE_FC_GLOBAL */ +#define ACE_FC_SSS_RESET (1 << 0) +#define ACE_FC_DMA_RESET (1 << 1) +#define ACE_FC_AES_RESET (1 << 2) +#define ACE_FC_DES_RESET (1 << 3) +#define ACE_FC_HASH_RESET (1 << 4) +#define ACE_FC_AXI_ENDIAN_MASK (3 << 6) +#define ACE_FC_AXI_ENDIAN_LE (0 << 6) +#define ACE_FC_AXI_ENDIAN_BIBE (1 << 6) +#define ACE_FC_AXI_ENDIAN_WIBE (2 << 6) + +/* Feed control - BRDMA control */ +#define ACE_FC_BRDMACFLUSH_OFF (0 << 0) +#define ACE_FC_BRDMACFLUSH_ON (1 << 0) +#define ACE_FC_BRDMACSWAP_ON (1 << 1) +#define ACE_FC_BRDMACARPROT_MASK (0x7 << 2) +#define ACE_FC_BRDMACARPROT_OFS (2) +#define ACE_FC_BRDMACARCACHE_MASK (0xf << 5) +#define ACE_FC_BRDMACARCACHE_OFS (5) + +/* Feed control - BTDMA control */ +#define ACE_FC_BTDMACFLUSH_OFF (0 << 0) +#define ACE_FC_BTDMACFLUSH_ON (1 << 0) +#define ACE_FC_BTDMACSWAP_ON (1 << 1) +#define ACE_FC_BTDMACAWPROT_MASK (0x7 << 2) +#define ACE_FC_BTDMACAWPROT_OFS (2) +#define ACE_FC_BTDMACAWCACHE_MASK (0xf << 5) +#define ACE_FC_BTDMACAWCACHE_OFS (5) + +/* Feed control - HRDMA control */ +#define ACE_FC_HRDMACFLUSH_OFF (0 << 0) +#define ACE_FC_HRDMACFLUSH_ON (1 << 0) +#define ACE_FC_HRDMACSWAP_ON (1 << 1) +#define ACE_FC_HRDMACARPROT_MASK (0x7 << 2) +#define ACE_FC_HRDMACARPROT_OFS (2) +#define ACE_FC_HRDMACARCACHE_MASK (0xf << 5) +#define ACE_FC_HRDMACARCACHE_OFS (5) + +/* Feed control - PKDMA control */ +#define ACE_FC_PKDMACBYTESWAP_ON (1 << 3) +#define ACE_FC_PKDMACDESEND_ON (1 << 2) +#define ACE_FC_PKDMACTRANSMIT_ON (1 << 1) +#define ACE_FC_PKDMACFLUSH_ON (1 << 0) + +/* Feed control - PKDMA offset */ +#define ACE_FC_SRAMOFFSET_MASK (0xfff) + +/* AES control */ +#define ACE_AES_MODE_MASK (1 << 0) +#define ACE_AES_MODE_ENC (0 << 0) +#define ACE_AES_MODE_DEC (1 << 0) +#define ACE_AES_OPERMODE_MASK (3 << 1) +#define ACE_AES_OPERMODE_ECB (0 << 1) +#define ACE_AES_OPERMODE_CBC (1 << 1) +#define ACE_AES_OPERMODE_CTR (2 << 1) +#define ACE_AES_FIFO_MASK (1 << 3) +#define ACE_AES_FIFO_OFF (0 << 3) /* CPU mode */ +#define ACE_AES_FIFO_ON (1 << 3) /* FIFO mode */ +#define ACE_AES_KEYSIZE_MASK (3 << 4) +#define ACE_AES_KEYSIZE_128 (0 << 4) +#define ACE_AES_KEYSIZE_192 (1 << 4) +#define ACE_AES_KEYSIZE_256 (2 << 4) +#define ACE_AES_KEYCNGMODE_MASK (1 << 6) +#define ACE_AES_KEYCNGMODE_OFF (0 << 6) +#define ACE_AES_KEYCNGMODE_ON (1 << 6) +#define ACE_AES_SWAP_MASK (0x1f << 7) +#define ACE_AES_SWAPKEY_OFF (0 << 7) +#define ACE_AES_SWAPKEY_ON (1 << 7) +#define ACE_AES_SWAPCNT_OFF (0 << 8) +#define ACE_AES_SWAPCNT_ON (1 << 8) +#define ACE_AES_SWAPIV_OFF (0 << 9) +#define ACE_AES_SWAPIV_ON (1 << 9) +#define ACE_AES_SWAPDO_OFF (0 << 10) +#define ACE_AES_SWAPDO_ON (1 << 10) +#define ACE_AES_SWAPDI_OFF (0 << 11) +#define ACE_AES_SWAPDI_ON (1 << 11) +#define ACE_AES_COUNTERSIZE_MASK (3 << 12) +#define ACE_AES_COUNTERSIZE_128 (0 << 12) +#define ACE_AES_COUNTERSIZE_64 (1 << 12) +#define ACE_AES_COUNTERSIZE_32 (2 << 12) +#define ACE_AES_COUNTERSIZE_16 (3 << 12) + +/* AES status */ +#define ACE_AES_OUTRDY_MASK (1 << 0) +#define ACE_AES_OUTRDY_OFF (0 << 0) +#define ACE_AES_OUTRDY_ON (1 << 0) +#define ACE_AES_INRDY_MASK (1 << 1) +#define ACE_AES_INRDY_OFF (0 << 1) +#define ACE_AES_INRDY_ON (1 << 1) +#define ACE_AES_BUSY_MASK (1 << 2) +#define ACE_AES_BUSY_OFF (0 << 2) +#define ACE_AES_BUSY_ON (1 << 2) + +/* TDES control */ +#define ACE_TDES_MODE_MASK (1 << 0) +#define ACE_TDES_MODE_ENC (0 << 0) +#define ACE_TDES_MODE_DEC (1 << 0) +#define ACE_TDES_OPERMODE_MASK (1 << 1) +#define ACE_TDES_OPERMODE_ECB (0 << 1) +#define ACE_TDES_OPERMODE_CBC (1 << 1) +#define ACE_TDES_SEL_MASK (3 << 3) +#define ACE_TDES_SEL_DES (0 << 3) +#define ACE_TDES_SEL_TDESEDE (1 << 3) /* TDES EDE mode */ +#define ACE_TDES_SEL_TDESEEE (3 << 3) /* TDES EEE mode */ +#define ACE_TDES_FIFO_MASK (1 << 5) +#define ACE_TDES_FIFO_OFF (0 << 5) /* CPU mode */ +#define ACE_TDES_FIFO_ON (1 << 5) /* FIFO mode */ +#define ACE_TDES_SWAP_MASK (0xf << 6) +#define ACE_TDES_SWAPKEY_OFF (0 << 6) +#define ACE_TDES_SWAPKEY_ON (1 << 6) +#define ACE_TDES_SWAPIV_OFF (0 << 7) +#define ACE_TDES_SWAPIV_ON (1 << 7) +#define ACE_TDES_SWAPDO_OFF (0 << 8) +#define ACE_TDES_SWAPDO_ON (1 << 8) +#define ACE_TDES_SWAPDI_OFF (0 << 9) +#define ACE_TDES_SWAPDI_ON (1 << 9) + +/* TDES status */ +#define ACE_TDES_OUTRDY_MASK (1 << 0) +#define ACE_TDES_OUTRDY_OFF (0 << 0) +#define ACE_TDES_OUTRDY_ON (1 << 0) +#define ACE_TDES_INRDY_MASK (1 << 1) +#define ACE_TDES_INRDY_OFF (0 << 1) +#define ACE_TDES_INRDY_ON (1 << 1) +#define ACE_TDES_BUSY_MASK (1 << 2) +#define ACE_TDES_BUSY_OFF (0 << 2) +#define ACE_TDES_BUSY_ON (1 << 2) + +/* Hash control */ +#define ACE_HASH_ENGSEL_MASK (0xf << 0) +#define ACE_HASH_ENGSEL_SHA1HASH (0x0 << 0) +#define ACE_HASH_ENGSEL_SHA1HMAC (0x1 << 0) +#define ACE_HASH_ENGSEL_SHA1HMACIN (0x1 << 0) +#define ACE_HASH_ENGSEL_SHA1HMACOUT (0x9 << 0) +#define ACE_HASH_ENGSEL_MD5HASH (0x2 << 0) +#define ACE_HASH_ENGSEL_MD5HMAC (0x3 << 0) +#define ACE_HASH_ENGSEL_MD5HMACIN (0x3 << 0) +#define ACE_HASH_ENGSEL_MD5HMACOUT (0xb << 0) +#define ACE_HASH_ENGSEL_SHA256HASH (0x4 << 0) +#define ACE_HASH_ENGSEL_SHA256HMAC (0x5 << 0) +#define ACE_HASH_ENGSEL_PRNG (0x8 << 0) +#define ACE_HASH_STARTBIT_ON (1 << 4) +#define ACE_HASH_USERIV_EN (1 << 5) + +/* Hash control 2 */ +#define ACE_HASH_PAUSE_ON (1 << 0) + +/* Hash control - FIFO mode */ +#define ACE_HASH_FIFO_MASK (1 << 0) +#define ACE_HASH_FIFO_OFF (0 << 0) +#define ACE_HASH_FIFO_ON (1 << 0) + +/* Hash control - byte swap */ +#define ACE_HASH_SWAP_MASK (0xf << 0) +#define ACE_HASH_SWAPKEY_OFF (0 << 0) +#define ACE_HASH_SWAPKEY_ON (1 << 0) +#define ACE_HASH_SWAPIV_OFF (0 << 1) +#define ACE_HASH_SWAPIV_ON (1 << 1) +#define ACE_HASH_SWAPDO_OFF (0 << 2) +#define ACE_HASH_SWAPDO_ON (1 << 2) +#define ACE_HASH_SWAPDI_OFF (0 << 3) +#define ACE_HASH_SWAPDI_ON (1 << 3) + +/* Hash status */ +#define ACE_HASH_BUFRDY_MASK (1 << 0) +#define ACE_HASH_BUFRDY_OFF (0 << 0) +#define ACE_HASH_BUFRDY_ON (1 << 0) +#define ACE_HASH_SEEDSETTING_MASK (1 << 1) +#define ACE_HASH_SEEDSETTING_OFF (0 << 1) +#define ACE_HASH_SEEDSETTING_ON (1 << 1) +#define ACE_HASH_PRNGBUSY_MASK (1 << 2) +#define ACE_HASH_PRNGBUSY_OFF (0 << 2) +#define ACE_HASH_PRNGBUSY_ON (1 << 2) +#define ACE_HASH_PARTIALDONE_MASK (1 << 4) +#define ACE_HASH_PARTIALDONE_OFF (0 << 4) +#define ACE_HASH_PARTIALDONE_ON (1 << 4) +#define ACE_HASH_PRNGDONE_MASK (1 << 5) +#define ACE_HASH_PRNGDONE_OFF (0 << 5) +#define ACE_HASH_PRNGDONE_ON (1 << 5) +#define ACE_HASH_MSGDONE_MASK (1 << 6) +#define ACE_HASH_MSGDONE_OFF (0 << 6) +#define ACE_HASH_MSGDONE_ON (1 << 6) +#define ACE_HASH_PRNGERROR_MASK (1 << 7) +#define ACE_HASH_PRNGERROR_OFF (0 << 7) +#define ACE_HASH_PRNGERROR_ON (1 << 7) + +#endif diff --git a/src/include/cpu/samsung/exynos5250/ace_sha.h b/src/include/cpu/samsung/exynos5250/ace_sha.h new file mode 100644 index 0000000..ed4e4d5 --- /dev/null +++ b/src/include/cpu/samsung/exynos5250/ace_sha.h @@ -0,0 +1,41 @@ +/* + * Header file for SHA firmware + * + * Copyright (c) 2012 Samsung Electronics + * + * 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 __ACE_FW_SHA1_H +#define __ACE_FW_SHA1_H + +#define ACE_SHA_TYPE_SHA1 1 +#define ACE_SHA_TYPE_SHA256 2 + +/** + * Computes hash value of input pbuf using ACE + * + * @param pout A pointer to the output buffer. When complete + * 32 bytes are copied to pout[0]...pout[31]. Thus, a user + * should allocate at least 32 bytes at pOut in advance. + * @param pbuf A pointer to the input buffer + * @param buflen Byte length of input buffer + * @param hash_type SHA1 or SHA256 + * + * @return 0 Success + */ +int ace_sha_hash_digest(uchar *pout, uchar *pbuf, uint buflen, uint hash_type); + +#endif diff --git a/src/include/cpu/samsung/exynos5250/adc.h b/src/include/cpu/samsung/exynos5250/adc.h new file mode 100644 index 0000000..86fcb88 --- /dev/null +++ b/src/include/cpu/samsung/exynos5250/adc.h @@ -0,0 +1,27 @@ +/* + * (C) Copyright 2012 Samsung Electronics + * Minkyu Kang mk7.kang@samsung.com + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + */ + +#ifndef __ASM_ARM_ARCH_EXYNOS5_ADC_H__ +#define __ASM_ARM_ARCH_EXYNOS5_ADC_H__ + +#include <asm/arch-exynos/adc.h> + +#endif /* __ASM_ARM_ARCH_EXYNOS5_ADC_H__ */ diff --git a/src/include/cpu/samsung/exynos5250/clk.h b/src/include/cpu/samsung/exynos5250/clk.h new file mode 100644 index 0000000..91b54fd --- /dev/null +++ b/src/include/cpu/samsung/exynos5250/clk.h @@ -0,0 +1,586 @@ +/* + * (C) Copyright 2012 Samsung Electronics + * Minkyu Kang mk7.kang@samsung.com + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + */ + +#ifndef __EXYNOS5_CLK_H__ +#define __EXYNOS5_CLK_H__ + +#include <cpu/samsung/exynos-common/clk.h> +#include <cpu/samsung/exynos5250/pinmux.h> + +/* + * Set mshci controller instances clock drivder + * + * @param enum periph_id instance of the mshci controller + * + * Return 0 if ok else -1 + */ +int clock_set_mshci(enum periph_id peripheral); + +/* + * Sets the epll clockrate + * + * @param rate Required clock rate to the presacaler in Hz + * + * Return 0 if ok else -1 + */ +int clock_epll_set_rate(unsigned long rate); + +/* + * selects the clk source for I2S MCLK + */ +void clock_select_i2s_clk_source(void); + +/* + * Set prescaler division based on input and output frequency + * for i2s audio clock + * + * @param src_frq Source frequency in Hz + * @param dst_frq Required MCLK frequency in Hz + * + * Return 0 if ok else -1 + */ +int clock_set_i2s_clk_prescaler(unsigned int src_frq, unsigned int dst_frq); + +/* FIXME(dhendrix): below is stuff from arch/arm/include/asm/arch-exynos5/clock.h + (as opposed to the two clk.h files as they were named in u-boot... */ +struct exynos5_clock { + unsigned int apll_lock; /* base + 0 */ + unsigned char res1[0xfc]; + unsigned int apll_con0; + unsigned int apll_con1; + unsigned char res2[0xf8]; + unsigned int src_cpu; + unsigned char res3[0x1fc]; + unsigned int mux_stat_cpu; + unsigned char res4[0xfc]; + unsigned int div_cpu0; + unsigned int div_cpu1; + unsigned char res5[0xf8]; + unsigned int div_stat_cpu0; + unsigned int div_stat_cpu1; + unsigned char res6[0x1f8]; + unsigned int gate_sclk_cpu; + unsigned char res7[0x1fc]; + unsigned int clkout_cmu_cpu; + unsigned int clkout_cmu_cpu_div_stat; + unsigned char res8[0x5f8]; + + unsigned int armclk_stopctrl; /* base + 0x1000 */ + unsigned int atclk_stopctrl; + unsigned char res9[0x8]; + unsigned int parityfail_status; + unsigned int parityfail_clear; + unsigned char res10[0x8]; + unsigned int pwr_ctrl; + unsigned int pwr_ctr2; + unsigned char res11[0xd8]; + unsigned int apll_con0_l8; + unsigned int apll_con0_l7; + unsigned int apll_con0_l6; + unsigned int apll_con0_l5; + unsigned int apll_con0_l4; + unsigned int apll_con0_l3; + unsigned int apll_con0_l2; + unsigned int apll_con0_l1; + unsigned int iem_control; + unsigned char res12[0xdc]; + unsigned int apll_con1_l8; + unsigned int apll_con1_l7; + unsigned int apll_con1_l6; + unsigned int apll_con1_l5; + unsigned int apll_con1_l4; + unsigned int apll_con1_l3; + unsigned int apll_con1_l2; + unsigned int apll_con1_l1; + unsigned char res13[0xe0]; + unsigned int div_iem_l8; + unsigned int div_iem_l7; + unsigned int div_iem_l6; + unsigned int div_iem_l5; + unsigned int div_iem_l4; + unsigned int div_iem_l3; + unsigned int div_iem_l2; + unsigned int div_iem_l1; + unsigned char res14[0x2ce0]; + + unsigned int mpll_lock; /* base + 0x4000 */ + unsigned char res15[0xfc]; + unsigned int mpll_con0; + unsigned int mpll_con1; + unsigned char res16[0xf8]; + unsigned int src_core0; + unsigned int src_core1; + unsigned char res17[0xf8]; + unsigned int src_mask_core; + unsigned char res18[0x100]; + unsigned int mux_stat_core1; + unsigned char res19[0xf8]; + unsigned int div_core0; + unsigned int div_core1; + unsigned int div_sysrgt; + unsigned char res20[0xf4]; + unsigned int div_stat_core0; + unsigned int div_stat_core1; + unsigned int div_stat_sysrgt; + unsigned char res21[0x2f4]; + unsigned int gate_ip_core; + unsigned int gate_ip_sysrgt; + unsigned char res22[0xf8]; + unsigned int clkout_cmu_core; + unsigned int clkout_cmu_core_div_stat; + unsigned char res23[0x5f8]; + + unsigned int dcgidx_map0; /* base + 0x5000 */ + unsigned int dcgidx_map1; + unsigned int dcgidx_map2; + unsigned char res24[0x14]; + unsigned int dcgperf_map0; + unsigned int dcgperf_map1; + unsigned char res25[0x18]; + unsigned int dvcidx_map; + unsigned char res26[0x1c]; + unsigned int freq_cpu; + unsigned int freq_dpm; + unsigned char res27[0x18]; + unsigned int dvsemclk_en; + unsigned int maxperf; + unsigned char res28[0x3478]; + + unsigned int div_acp; /* base + 0x8500 */ + unsigned char res29[0xfc]; + unsigned int div_stat_acp; + unsigned char res30[0x1fc]; + unsigned int gate_ip_acp; + unsigned char res31a[0xfc]; + unsigned int div_syslft; + unsigned char res31b[0xc]; + unsigned int div_stat_syslft; + unsigned char res31c[0xc]; + unsigned int gate_bus_syslft; + unsigned char res31d[0xdc]; + unsigned int clkout_cmu_acp; + unsigned int clkout_cmu_acp_div_stat; + unsigned char res32[0x38f8]; + + unsigned int div_isp0; /* base + 0xc300 */ + unsigned int div_isp1; + unsigned int div_isp2; + unsigned char res33[0xf4]; + + unsigned int div_stat_isp0; /* base + 0xc400 */ + unsigned int div_stat_isp1; + unsigned int div_stat_isp2; + unsigned char res34[0x3f4]; + + unsigned int gate_ip_isp0; /* base + 0xc800 */ + unsigned int gate_ip_isp1; + unsigned char res35[0xf8]; + unsigned int gate_sclk_isp; + unsigned char res36[0xc]; + unsigned int mcuisp_pwr_ctrl; + unsigned char res37[0xec]; + unsigned int clkout_cmu_isp; + unsigned int clkout_cmu_isp_div_stat; + unsigned char res38[0x3618]; + + unsigned int cpll_lock; /* base + 0x10020 */ + unsigned char res39[0xc]; + unsigned int epll_lock; + unsigned char res40[0xc]; + unsigned int vpll_lock; + unsigned char res41a[0xc]; + unsigned int gpll_lock; + unsigned char res41b[0xcc]; + unsigned int cpll_con0; + unsigned int cpll_con1; + unsigned char res42[0x8]; + unsigned int epll_con0; + unsigned int epll_con1; + unsigned int epll_con2; + unsigned char res43[0x4]; + unsigned int vpll_con0; + unsigned int vpll_con1; + unsigned int vpll_con2; + unsigned char res44a[0x4]; + unsigned int gpll_con0; + unsigned int gpll_con1; + unsigned char res44b[0xb8]; + unsigned int src_top0; + unsigned int src_top1; + unsigned int src_top2; + unsigned int src_top3; + unsigned int src_gscl; + unsigned int src_disp0_0; + unsigned int src_disp0_1; + unsigned int src_disp1_0; + unsigned int src_disp1_1; + unsigned char res46[0xc]; + unsigned int src_mau; + unsigned int src_fsys; + unsigned char res47[0x8]; + unsigned int src_peric0; + unsigned int src_peric1; + unsigned char res48[0x18]; + unsigned int sclk_src_isp; + unsigned char res49[0x9c]; + unsigned int src_mask_top; + unsigned char res50[0xc]; + unsigned int src_mask_gscl; + unsigned int src_mask_disp0_0; + unsigned int src_mask_disp0_1; + unsigned int src_mask_disp1_0; + unsigned int src_mask_disp1_1; + unsigned int src_mask_maudio; + unsigned char res52[0x8]; + unsigned int src_mask_fsys; + unsigned char res53[0xc]; + unsigned int src_mask_peric0; + unsigned int src_mask_peric1; + unsigned char res54[0x18]; + unsigned int src_mask_isp; + unsigned char res55[0x9c]; + unsigned int mux_stat_top0; + unsigned int mux_stat_top1; + unsigned int mux_stat_top2; + unsigned int mux_stat_top3; + unsigned char res56[0xf0]; + unsigned int div_top0; + unsigned int div_top1; + unsigned char res57[0x8]; + unsigned int div_gscl; + unsigned int div_disp0_0; + unsigned int div_disp0_1; + unsigned int div_disp1_0; + unsigned int div_disp1_1; + unsigned char res59[0x8]; + unsigned int div_gen; + unsigned char res60[0x4]; + unsigned int div_mau; + unsigned int div_fsys0; + unsigned int div_fsys1; + unsigned int div_fsys2; + unsigned int div_fsys3; + unsigned int div_peric0; + unsigned int div_peric1; + unsigned int div_peric2; + unsigned int div_peric3; + unsigned int div_peric4; + unsigned int div_peric5; + unsigned char res61[0x10]; + unsigned int sclk_div_isp; + unsigned char res62[0xc]; + unsigned int div2_ratio0; + unsigned int div2_ratio1; + unsigned char res63[0x8]; + unsigned int div4_ratio; + unsigned char res64[0x6c]; + unsigned int div_stat_top0; + unsigned int div_stat_top1; + unsigned char res65[0x8]; + unsigned int div_stat_gscl; + unsigned int div_stat_disp0_0; + unsigned int div_stat_disp0_1; + unsigned int div_stat_disp1_0; + unsigned int div_stat_disp1_1; + unsigned char res67[0x8]; + unsigned int div_stat_gen; + unsigned char res68[0x4]; + unsigned int div_stat_maudio; + unsigned int div_stat_fsys0; + unsigned int div_stat_fsys1; + unsigned int div_stat_fsys2; + unsigned int div_stat_fsys3; + unsigned int div_stat_peric0; + unsigned int div_stat_peric1; + unsigned int div_stat_peric2; + unsigned int div_stat_peric3; + unsigned int div_stat_peric4; + unsigned int div_stat_peric5; + unsigned char res69[0x10]; + unsigned int sclk_div_stat_isp; + unsigned char res70[0xc]; + unsigned int div2_stat0; + unsigned int div2_stat1; + unsigned char res71[0x8]; + unsigned int div4_stat; + unsigned char res72[0x180]; + unsigned int gate_top_sclk_disp0; + unsigned int gate_top_sclk_disp1; + unsigned int gate_top_sclk_gen; + unsigned char res74[0xc]; + unsigned int gate_top_sclk_mau; + unsigned int gate_top_sclk_fsys; + unsigned char res75[0xc]; + unsigned int gate_top_sclk_peric; + unsigned char res76[0x1c]; + unsigned int gate_top_sclk_isp; + unsigned char res77[0xac]; + unsigned int gate_ip_gscl; + unsigned int gate_ip_disp0; + unsigned int gate_ip_disp1; + unsigned int gate_ip_mfc; + unsigned int gate_ip_g3d; + unsigned int gate_ip_gen; + unsigned char res79[0xc]; + unsigned int gate_ip_fsys; + unsigned char res80[0x4]; + unsigned int gate_ip_gps; + unsigned int gate_ip_peric; + unsigned char res81[0xc]; + unsigned int gate_ip_peris; + unsigned char res82[0x1c]; + unsigned int gate_block; + unsigned char res83[0x7c]; + unsigned int clkout_cmu_top; + unsigned int clkout_cmu_top_div_stat; + unsigned char res84[0x37f8]; + + unsigned int src_lex; /* base + 0x14200 */ + unsigned char res85[0x1fc]; + unsigned int mux_stat_lex; + unsigned char res85b[0xfc]; + unsigned int div_lex; + unsigned char res86[0xfc]; + unsigned int div_stat_lex; + unsigned char res87[0x1fc]; + unsigned int gate_ip_lex; + unsigned char res88[0x1fc]; + unsigned int clkout_cmu_lex; + unsigned int clkout_cmu_lex_div_stat; + unsigned char res89[0x3af8]; + + unsigned int div_r0x; /* base + 0x18500 */ + unsigned char res90[0xfc]; + unsigned int div_stat_r0x; + unsigned char res91[0x1fc]; + unsigned int gate_ip_r0x; + unsigned char res92[0x1fc]; + unsigned int clkout_cmu_r0x; + unsigned int clkout_cmu_r0x_div_stat; + unsigned char res94[0x3af8]; + + unsigned int div_r1x; /* base + 0x1c500 */ + unsigned char res95[0xfc]; + unsigned int div_stat_r1x; + unsigned char res96[0x1fc]; + unsigned int gate_ip_r1x; + unsigned char res97[0x1fc]; + unsigned int clkout_cmu_r1x; + unsigned int clkout_cmu_r1x_div_stat; + unsigned char res98[0x3608]; + + unsigned int bpll_lock; /* base + 0x2000c */ + unsigned char res99[0xfc]; + unsigned int bpll_con0; + unsigned int bpll_con1; + unsigned char res100[0xe8]; + unsigned int src_cdrex; + unsigned char res101[0x1fc]; + unsigned int mux_stat_cdrex; + unsigned char res102[0xfc]; + unsigned int div_cdrex; + unsigned int div_cdrex2; + unsigned char res103[0xf8]; + unsigned int div_stat_cdrex; + unsigned char res104[0x2fc]; + unsigned int gate_ip_cdrex; + unsigned char res105[0xc]; + unsigned int c2c_monitor; + unsigned int dmc_pwr_ctrl; + unsigned char res106[0x4]; + unsigned int drex2_pause; + unsigned char res107[0xe0]; + unsigned int clkout_cmu_cdrex; + unsigned int clkout_cmu_cdrex_div_stat; + unsigned char res108[0x8]; + unsigned int lpddr3phy_ctrl; + unsigned char res109a[0xc]; + unsigned int lpddr3phy_con3; + unsigned int pll_div2_sel; + unsigned char res109b[0xf5e4]; +}; + +struct exynos5_mct_regs { + uint32_t mct_cfg; + uint8_t reserved0[0xfc]; + uint32_t g_cnt_l; + uint32_t g_cnt_u; + uint8_t reserved1[0x8]; + uint32_t g_cnt_wstat; + uint8_t reserved2[0xec]; + uint32_t g_comp0_l; + uint32_t g_comp0_u; + uint32_t g_comp0_addr_incr; + uint8_t reserved3[0x4]; + uint32_t g_comp1_l; + uint32_t g_comp1_u; + uint32_t g_comp1_addr_incr; + uint8_t reserved4[0x4]; + uint32_t g_comp2_l; + uint32_t g_comp2_u; + uint32_t g_comp2_addr_incr; + uint8_t reserved5[0x4]; + uint32_t g_comp3_l; + uint32_t g_comp3_u; + uint32_t g_comp3_addr_incr; + uint8_t reserved6[0x4]; + uint32_t g_tcon; + uint32_t g_int_cstat; + uint32_t g_int_enb; + uint32_t g_wstat; + uint8_t reserved7[0xb0]; + uint32_t l0_tcntb; + uint32_t l0_tcnto; + uint32_t l0_icntb; + uint32_t l0_icnto; + uint32_t l0_frcntb; + uint32_t l0_frcnto; + uint8_t reserved8[0x8]; + uint32_t l0_tcon; + uint8_t reserved9[0xc]; + uint32_t l0_int_cstat; + uint32_t l0_int_enb; + uint8_t reserved10[0x8]; + uint32_t l0_wstat; + uint8_t reserved11[0xbc]; + uint32_t l1_tcntb; + uint32_t l1_tcnto; + uint32_t l1_icntb; + uint32_t l1_icnto; + uint32_t l1_frcntb; + uint32_t l1_frcnto; + uint8_t reserved12[0x8]; + uint32_t l1_tcon; + uint8_t reserved13[0xc]; + uint32_t l1_int_cstat; + uint32_t l1_int_enb; + uint8_t reserved14[0x8]; + uint32_t l1_wstat; +}; + +#define EXYNOS5_EPLLCON0_LOCKED_SHIFT 29 /* EPLL Locked bit position*/ +#define EPLL_SRC_CLOCK 24000000 /*24 MHz Cristal Input */ +#define TIMEOUT_EPLL_LOCK 1000 + +#define AUDIO_0_RATIO_MASK 0x0f +#define AUDIO_1_RATIO_MASK 0x0f + +#define CLK_SRC_PERIC1 0x254 +#define AUDIO1_SEL_MASK 0xf +#define CLK_SRC_AUDIOCDCLK1 0x0 +#define CLK_SRC_XXTI 0x1 +#define CLK_SRC_SCLK_EPLL 0x7 + +/* CON0 bit-fields */ +#define EPLL_CON0_MDIV_MASK 0x1ff +#define EPLL_CON0_PDIV_MASK 0x3f +#define EPLL_CON0_SDIV_MASK 0x7 +#define EPLL_CON0_LOCKED_SHIFT 29 +#define EPLL_CON0_MDIV_SHIFT 16 +#define EPLL_CON0_PDIV_SHIFT 8 +#define EPLL_CON0_SDIV_SHIFT 0 +#define EPLL_CON0_LOCK_DET_EN_SHIFT 28 +#define EPLL_CON0_LOCK_DET_EN_MASK 1 + +/* structure for epll configuration used in audio clock configuration */ +struct st_epll_con_val { + unsigned int freq_out; /* frequency out */ + unsigned int en_lock_det; /* enable lock detect */ + unsigned int m_div; /* m divider value */ + unsigned int p_div; /* p divider value */ + unsigned int s_div; /* s divider value */ + unsigned int k_dsm; /* k value of delta signal modulator */ +}; + +/** + * Low-level function to set the clock pre-ratio for a peripheral + * + * @param periph_id Peripheral ID of peripheral to change + * @param divisor New divisor for this peripheral's clock + */ +void clock_ll_set_pre_ratio(enum periph_id periph_id, unsigned divisor); + +/** + * Low-level function to set the clock ratio for a peripheral + * + * @param periph_id Peripheral ID of peripheral to change + * @param divisor New divisor for this peripheral's clock + */ +void clock_ll_set_ratio(enum periph_id periph_id, unsigned divisor); + +/** + * Low-level function that selects the best clock scalars for a given rate and + * sets up the given peripheral's clock accordingly. + * + * @param periph_id Peripheral ID of peripheral to change + * @param rate Desired clock rate in Hz + * + * @return zero on success, negative on error + */ +int clock_set_rate(enum periph_id periph_id, unsigned int rate); + +/** + * Decode a peripheral ID from a device node. + * + * Drivers should always use this function since the actual means of + * encoding this information may change in the future as fdt support for + * exynos evolves. + * + * @param blob FDT blob to read from + * @param node Node containing the information + */ +int clock_decode_periph_id(const void *blob, int node); + +/* Clock gate unused IP */ +void clock_gate(void); + +enum ddr_mode; +enum mem_manuf; + +const char *clock_get_mem_type_name(enum ddr_mode mem_type); + +const char *clock_get_mem_manuf_name(enum mem_manuf mem_manuf); + +/* + * TODO(sjg@chromium.org): Remove this when we have more SPL space. + * At present we are using 14148 of 14336 bytes. If we change this function + * to be exported in SPL, we go over the edge. + */ +/* TODO(dhendrix): do we still need this ifndef? */ +//#ifndef CONFIG_SPL_BUILD +/** + * Get the required memory type and speed (Main U-Boot version). + * + * This should use the device tree. For now we cannot since this function is + * called before the FDT is available. + * + * @param mem_type Returns memory type + * @param frequency_mhz Returns memory speed in MHz + * @param arm_freq Returns ARM clock speed in MHz + * @param mem_manuf Return Memory Manufacturer name + * @return 0 if all ok (if not, this function currently does not return) + */ +int clock_get_mem_selection(enum ddr_mode *mem_type, + unsigned *frequency_mhz, unsigned *arm_freq, + enum mem_manuf *mem_manuf); +//#endif /* CONFIG_SPL_BUILD */ + +#endif diff --git a/src/include/cpu/samsung/exynos5250/cpu.h b/src/include/cpu/samsung/exynos5250/cpu.h new file mode 100644 index 0000000..f6d7c65 --- /dev/null +++ b/src/include/cpu/samsung/exynos5250/cpu.h @@ -0,0 +1,134 @@ +/* + * (C) Copyright 2010 Samsung Electronics + * Minkyu Kang mk7.kang@samsung.com + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + */ + +#ifndef _EXYNOS5250_CPU_H +#define _EXYNOS5250_CPU_H + +#include <cpu/samsung/exynos-common/cpu.h> + +/* EXYNOS5 */ +#define EXYNOS5_GPIO_PART6_BASE 0x03860000 /* Z<6:0> */ +#define EXYNOS5_PRO_ID 0x10000000 +#define EXYNOS5_CLOCK_BASE 0x10010000 +#define EXYNOS5_POWER_BASE 0x10040000 +#define EXYNOS5_SWRESET 0x10040400 +#define EXYNOS5_SYSREG_BASE 0x10050000 +#define EXYNOS5_TZPC1_DECPROT1SET 0x10110810 +#define EXYNOS5_MULTI_CORE_TIMER_BASE 0x101C0000 +#define EXYNOS5_WATCHDOG_BASE 0x101D0000 +#define EXYNOS5_ACE_SFR_BASE 0x10830000 +#define EXYNOS5_DMC_PHY0_BASE 0x10C00000 +#define EXYNOS5_DMC_PHY1_BASE 0x10C10000 +#define EXYNOS5_GPIO_PART4_BASE 0x10D10000 /* V00..V37 */ +#define EXYNOS5_GPIO_PART5_BASE 0x10D100C0 /* V40..V47 */ +#define EXYNOS5_DMC_CTRL_BASE 0x10DD0000 +#define EXYNOS5_GPIO_PART1_BASE 0x11400000 /* A00..Y67 */ +#define EXYNOS5_GPIO_PART2_BASE 0x11400c00 /* X00..X37 */ +#define EXYNOS5_USB_HOST_EHCI_BASE 0x12110000 +#define EXYNOS5_USBPHY_BASE 0x12130000 +#define EXYNOS5_USBOTG_BASE 0x12140000 + +#ifndef CONFIG_OF_CONTROL +#define EXYNOS5_MMC_BASE 0x12200000 +#define EXYNOS5_MSHC_BASE 0x12240000 +#endif + +#define EXYNOS5_SROMC_BASE 0x12250000 +#define EXYNOS5_UART_BASE 0x12C00000 + +#define EXYNOS5_SPI1_BASE 0x12D30000 +#ifndef CONFIG_OF_CONTROL +#define EXYNOS5_I2C_BASE 0x12C60000 +#define EXYNOS5_SPI_BASE 0x12D20000 +#define EXYNOS5_PWMTIMER_BASE 0x12DD0000 +#define EXYNOS5_SPI_ISP_BASE 0x131A0000 +#endif +#define EXYNOS5_I2S_BASE 0x12D60000 +#define EXYNOS5_GPIO_PART3_BASE 0x13400000 /* E00..H17 */ +#define EXYNOS5_FIMD_BASE 0x14400000 +#define EXYNOS5_DISP1_CTRL_BASE 0x14420000 +#define EXYNOS5_MIPI_DSI1_BASE 0x14500000 + +#define EXYNOS5_ADC_BASE DEVICE_NOT_AVAILABLE +#define EXYNOS5_MODEM_BASE DEVICE_NOT_AVAILABLE + +/* Compatibility defines */ +#define EXYNOS_POWER_BASE EXYNOS5_POWER_BASE + +/* Marker values stored at the bottom of IRAM stack by SPL */ +#define EXYNOS5_SPL_MARKER 0xb004f1a9 /* hexspeak word: bootflag */ + +/* Distance between each Trust Zone PC register set */ +#define TZPC_BASE_OFFSET 0x10000 + +#ifndef __ASSEMBLY__ + +#define SAMSUNG_BASE(device, base) \ +static inline unsigned int samsung_get_base_##device(void) \ +{ \ + return cpu_is_exynos5() ? EXYNOS5_##base : 0; \ +} + +SAMSUNG_BASE(adc, ADC_BASE) +SAMSUNG_BASE(clock, CLOCK_BASE) +SAMSUNG_BASE(ace_sfr, ACE_SFR_BASE) +SAMSUNG_BASE(dsim, MIPI_DSI1_BASE) +SAMSUNG_BASE(disp_ctrl, DISP1_CTRL_BASE) +SAMSUNG_BASE(fimd, FIMD_BASE) +SAMSUNG_BASE(gpio_part1, GPIO_PART1_BASE) +SAMSUNG_BASE(gpio_part2, GPIO_PART2_BASE) +SAMSUNG_BASE(gpio_part3, GPIO_PART3_BASE) +SAMSUNG_BASE(gpio_part4, GPIO_PART4_BASE) +SAMSUNG_BASE(gpio_part5, GPIO_PART5_BASE) +SAMSUNG_BASE(gpio_part6, GPIO_PART6_BASE) +SAMSUNG_BASE(pro_id, PRO_ID) + +#ifndef CONFIG_OF_CONTROL +SAMSUNG_BASE(mmc, MMC_BASE) +SAMSUNG_BASE(mshci, MSHC_BASE) +#endif + +SAMSUNG_BASE(modem, MODEM_BASE) +SAMSUNG_BASE(sromc, SROMC_BASE) +SAMSUNG_BASE(swreset, SWRESET) +SAMSUNG_BASE(sysreg, SYSREG_BASE) +SAMSUNG_BASE(timer, PWMTIMER_BASE) +SAMSUNG_BASE(uart, UART_BASE) +SAMSUNG_BASE(usb_phy, USBPHY_BASE) +SAMSUNG_BASE(usb_otg, USBOTG_BASE) +SAMSUNG_BASE(watchdog, WATCHDOG_BASE) +SAMSUNG_BASE(power, POWER_BASE) +SAMSUNG_BASE(i2s, I2S_BASE) +SAMSUNG_BASE(spi1, SPI1_BASE) +#ifndef CONFIG_OF_CONTROL +SAMSUNG_BASE(i2c, I2C_BASE) +SAMSUNG_BASE(spi, SPI_BASE) +SAMSUNG_BASE(spi_isp, SPI_ISP_BASE) +#endif +#endif + +#define EXYNOS5_SPI_NUM_CONTROLLERS 5 +#define EXYNOS_I2C_MAX_CONTROLLERS 8 + +/* helper function to map mmio address to peripheral id */ +enum periph_id exynos5_get_periph_id(unsigned base_addr); + +#endif /* _EXYNOS5250_CPU_H */ diff --git a/src/include/cpu/samsung/exynos5250/dmc.h b/src/include/cpu/samsung/exynos5250/dmc.h new file mode 100644 index 0000000..d1dfbb1 --- /dev/null +++ b/src/include/cpu/samsung/exynos5250/dmc.h @@ -0,0 +1,211 @@ +#ifndef __DMC_H__ +#define __DMC_H__ + +#ifndef __ASSEMBLER__ +struct exynos5_dmc { + unsigned int concontrol; + unsigned int memcontrol; + unsigned int memconfig0; + unsigned int memconfig1; + unsigned int directcmd; + unsigned int prechconfig; + unsigned int phycontrol0; + unsigned char res1[0xc]; + unsigned int pwrdnconfig; + unsigned int timingpzq; + unsigned int timingref; + unsigned int timingrow; + unsigned int timingdata; + unsigned int timingpower; + unsigned int phystatus; + unsigned char res2[0x4]; + unsigned int chipstatus_ch0; + unsigned int chipstatus_ch1; + unsigned char res3[0x4]; + unsigned int mrstatus; + unsigned char res4[0x8]; + unsigned int qoscontrol0; + unsigned char resr5[0x4]; + unsigned int qoscontrol1; + unsigned char res6[0x4]; + unsigned int qoscontrol2; + unsigned char res7[0x4]; + unsigned int qoscontrol3; + unsigned char res8[0x4]; + unsigned int qoscontrol4; + unsigned char res9[0x4]; + unsigned int qoscontrol5; + unsigned char res10[0x4]; + unsigned int qoscontrol6; + unsigned char res11[0x4]; + unsigned int qoscontrol7; + unsigned char res12[0x4]; + unsigned int qoscontrol8; + unsigned char res13[0x4]; + unsigned int qoscontrol9; + unsigned char res14[0x4]; + unsigned int qoscontrol10; + unsigned char res15[0x4]; + unsigned int qoscontrol11; + unsigned char res16[0x4]; + unsigned int qoscontrol12; + unsigned char res17[0x4]; + unsigned int qoscontrol13; + unsigned char res18[0x4]; + unsigned int qoscontrol14; + unsigned char res19[0x4]; + unsigned int qoscontrol15; + unsigned char res20[0x14]; + unsigned int ivcontrol; + unsigned int wrtra_config; + unsigned int rdlvl_config; + unsigned char res21[0x8]; + unsigned int brbrsvconfig; + unsigned int brbqosconfig; + unsigned int membaseconfig0; + unsigned int membaseconfig1; + unsigned char res22[0xc]; + unsigned int wrlvl_config; + unsigned char res23[0xc]; + unsigned int perevcontrol; + unsigned int perev0config; + unsigned int perev1config; + unsigned int perev2config; + unsigned int perev3config; + unsigned char res24[0xdebc]; + unsigned int pmnc_ppc_a; + unsigned char res25[0xc]; + unsigned int cntens_ppc_a; + unsigned char res26[0xc]; + unsigned int cntenc_ppc_a; + unsigned char res27[0xc]; + unsigned int intens_ppc_a; + unsigned char res28[0xc]; + unsigned int intenc_ppc_a; + unsigned char res29[0xc]; + unsigned int flag_ppc_a; + unsigned char res30[0xac]; + unsigned int ccnt_ppc_a; + unsigned char res31[0xc]; + unsigned int pmcnt0_ppc_a; + unsigned char res32[0xc]; + unsigned int pmcnt1_ppc_a; + unsigned char res33[0xc]; + unsigned int pmcnt2_ppc_a; + unsigned char res34[0xc]; + unsigned int pmcnt3_ppc_a; +}; + +struct exynos5_phy_control { + unsigned int phy_con0; + unsigned int phy_con1; + unsigned int phy_con2; + unsigned int phy_con3; + unsigned int phy_con4; + unsigned char res1[4]; + unsigned int phy_con6; + unsigned char res2[4]; + unsigned int phy_con8; + unsigned int phy_con9; + unsigned int phy_con10; + unsigned char res3[4]; + unsigned int phy_con12; + unsigned int phy_con13; + unsigned int phy_con14; + unsigned int phy_con15; + unsigned int phy_con16; + unsigned char res4[4]; + unsigned int phy_con17; + unsigned int phy_con18; + unsigned int phy_con19; + unsigned int phy_con20; + unsigned int phy_con21; + unsigned int phy_con22; + unsigned int phy_con23; + unsigned int phy_con24; + unsigned int phy_con25; + unsigned int phy_con26; + unsigned int phy_con27; + unsigned int phy_con28; + unsigned int phy_con29; + unsigned int phy_con30; + unsigned int phy_con31; + unsigned int phy_con32; + unsigned int phy_con33; + unsigned int phy_con34; + unsigned int phy_con35; + unsigned int phy_con36; + unsigned int phy_con37; + unsigned int phy_con38; + unsigned int phy_con39; + unsigned int phy_con40; + unsigned int phy_con41; + unsigned int phy_con42; +}; + +enum ddr_mode { + DDR_MODE_DDR2, + DDR_MODE_DDR3, + DDR_MODE_LPDDR2, + DDR_MODE_LPDDR3, + + DDR_MODE_COUNT, +}; + +enum mem_manuf { + MEM_MANUF_AUTODETECT, + MEM_MANUF_ELPIDA, + MEM_MANUF_SAMSUNG, + + MEM_MANUF_COUNT, +}; + +/* CONCONTROL register fields */ +#define CONCONTROL_DFI_INIT_START_SHIFT 28 +#define CONCONTROL_RD_FETCH_SHIFT 12 +#define CONCONTROL_RD_FETCH_MASK (0x7 << CONCONTROL_RD_FETCH_SHIFT) +#define CONCONTROL_AREF_EN_SHIFT 5 + +/* PRECHCONFIG register field */ +#define PRECHCONFIG_TP_CNT_SHIFT 24 + +/* PWRDNCONFIG register field */ +#define PWRDNCONFIG_DPWRDN_CYC_SHIFT 0 +#define PWRDNCONFIG_DSREF_CYC_SHIFT 16 + +/* PHY_CON0 register fields */ +#define PHY_CON0_T_WRRDCMD_SHIFT 17 +#define PHY_CON0_T_WRRDCMD_MASK (0x7 << PHY_CON0_T_WRRDCMD_SHIFT) +#define PHY_CON0_CTRL_DDR_MODE_SHIFT 11 + +/* PHY_CON1 register fields */ +#define PHY_CON1_RDLVL_RDDATA_ADJ_SHIFT 0 + +/* PHY_CON12 register fields */ +#define PHY_CON12_CTRL_START_POINT_SHIFT 24 +#define PHY_CON12_CTRL_INC_SHIFT 16 +#define PHY_CON12_CTRL_FORCE_SHIFT 8 +#define PHY_CON12_CTRL_START_SHIFT 6 +#define PHY_CON12_CTRL_START_MASK (1 << PHY_CON12_CTRL_START_SHIFT) +#define PHY_CON12_CTRL_DLL_ON_SHIFT 5 +#define PHY_CON12_CTRL_DLL_ON_MASK (1 << PHY_CON12_CTRL_DLL_ON_SHIFT) +#define PHY_CON12_CTRL_REF_SHIFT 1 + +/* PHY_CON16 register fields */ +#define PHY_CON16_ZQ_MODE_DDS_SHIFT 24 +#define PHY_CON16_ZQ_MODE_DDS_MASK (0x7 << PHY_CON16_ZQ_MODE_DDS_SHIFT) + +#define PHY_CON16_ZQ_MODE_TERM_SHIFT 21 +#define PHY_CON16_ZQ_MODE_TERM_MASK (0x7 << PHY_CON16_ZQ_MODE_TERM_SHIFT) + +#define PHY_CON16_ZQ_MODE_NOTERM_MASK (1 << 19) + +/* PHY_CON42 register fields */ +#define PHY_CON42_CTRL_BSTLEN_SHIFT 8 +#define PHY_CON42_CTRL_BSTLEN_MASK (0xff << PHY_CON42_CTRL_BSTLEN_SHIFT) + +#define PHY_CON42_CTRL_RDLAT_SHIFT 0 +#define PHY_CON42_CTRL_RDLAT_MASK (0x1f << PHY_CON42_CTRL_RDLAT_SHIFT) + +#endif +#endif diff --git a/src/include/cpu/samsung/exynos5250/dsim.h b/src/include/cpu/samsung/exynos5250/dsim.h new file mode 100644 index 0000000..38a4c98 --- /dev/null +++ b/src/include/cpu/samsung/exynos5250/dsim.h @@ -0,0 +1,108 @@ +/* + * (C) Copyright 2012 Samsung Electronics + * Register map for Exynos5 MIPI-DSIM + * + * 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 __EXYNOS5_DSIM_H__ +#define __EXYNOS5_DSIM_H__ + +/* DSIM register map */ +struct exynos5_dsim { + unsigned int status; + unsigned int swrst; + unsigned int clkctrl; + unsigned int timeout; + unsigned int config; + unsigned int escmode; + unsigned int mdresol; + unsigned int mvporch; + unsigned int mhporch; + unsigned int msync; + unsigned int sdresol; + unsigned int intsrc; + unsigned int intmsk; + unsigned int pkthdr; + unsigned int payload; + unsigned int rxfifo; + unsigned int res1; + unsigned int fifoctrl; + unsigned int res2; + unsigned int pllctrl; + unsigned int plltmr; + unsigned int phyacchr; + unsigned int phyacchr1; +}; + +#define ENABLE 1 +#define DISABLE 0 + +#define DSIM_SWRST (1 << 0) +#define NUM_OF_DAT_LANE_IS_FOUR (3 << 5) +#define DATA_LANE_0_EN (1 << 0) +#define DATA_LANE_1_EN (1 << 1) +#define DATA_LANE_2_EN (1 << 2) +#define DATA_LANE_3_EN (1 << 3) +#define CLK_LANE_EN (1 << 4) +#define ENABLE_ALL_DATA_LANE DATA_LANE_0_EN | \ + DATA_LANE_1_EN | \ + DATA_LANE_2_EN | \ + DATA_LANE_3_EN +#define MAIN_PIX_FORMAT_OFFSET 12 +#define RGB_565_16_BIT 0x4 +#define VIDEO_MODE (1 << 25) +#define BURST_MODE (1 << 26) + + +#define DSIM_PHYACCHR_AFC_EN (1 << 14) +#define DSIM_PHYACCHR_AFC_CTL_OFFSET 5 + +#define DSIM_PLLCTRL_PMS_OFFSET 1 +#define DSIM_FREQ_BAND_OFFSET 24 + +#define LANE_ESC_CLK_EN_ALL (0x1f << 19) +#define BYTE_CLK_EN (1 << 24) +#define DSIM_ESC_CLK_EN (1 << 28) +#define TXREQUEST_HS_CLK_ON (1 << 31) + +#define LP_MODE_ENABLE (1 << 7) +#define STOP_STATE_CNT_OFFSET 21 + +#define MAIN_VBP_OFFSET 0 +#define STABLE_VFP_OFFSET 16 +#define CMD_ALLOW_OFFSET 28 + +#define MAIN_HBP_OFFSET 0 +#define MAIN_HFP_OFFSET 16 + +#define MAIN_HSA_OFFSET 0 +#define MAIN_VSA_OFFSET 22 + +#define MAIN_STANDBY (1 << 31) +#define MAIN_VRESOL_OFFSET 16 +#define MAIN_HRESOL_OFFSET 0 + +#define SFR_FIFO_EMPTY (1 << 29) + +#define DSIM_PLL_EN_SHIFT (1 << 23) +#define PLL_STABLE (1 << 31) + +#define DSIM_STOP_STATE_DAT(x) (((x) & 0xf) << 0) +#define DSIM_STOP_STATE_CLK (1 << 8) +#define DSIM_TX_READY_HS_CLK (1 << 10) + +#endif diff --git a/src/include/cpu/samsung/exynos5250/ehci-s5p.h b/src/include/cpu/samsung/exynos5250/ehci-s5p.h new file mode 100644 index 0000000..56abb60 --- /dev/null +++ b/src/include/cpu/samsung/exynos5250/ehci-s5p.h @@ -0,0 +1,66 @@ +/* + * SAMSUNG S5P USB HOST EHCI Controller + * + * Copyright (C) 2012 Samsung Electronics Co.Ltd + * Vivek Gautam gautam.vivek@samsung.com + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301 USA + */ + +#ifndef __ASM_ARM_ARCH_EXYNOS5_EHCI_S5P_H__ +#define __ASM_ARM_ARCH_EXYNOS5_EHCI_S5P_H__ + +#define CLK_24MHZ 5 + +#define HOST_CTRL0_PHYSWRSTALL (1 << 31) +#define HOST_CTRL0_COMMONON_N (1 << 9) +#define HOST_CTRL0_SIDDQ (1 << 6) +#define HOST_CTRL0_FORCESLEEP (1 << 5) +#define HOST_CTRL0_FORCESUSPEND (1 << 4) +#define HOST_CTRL0_WORDINTERFACE (1 << 3) +#define HOST_CTRL0_UTMISWRST (1 << 2) +#define HOST_CTRL0_LINKSWRST (1 << 1) +#define HOST_CTRL0_PHYSWRST (1 << 0) + +#define HOST_CTRL0_FSEL_MASK (7 << 16) + +#define EHCICTRL_ENAINCRXALIGN (1 << 29) +#define EHCICTRL_ENAINCR4 (1 << 28) +#define EHCICTRL_ENAINCR8 (1 << 27) +#define EHCICTRL_ENAINCR16 (1 << 26) + +/* Register map for PHY control */ +struct usb_phy { + unsigned int usbphyctrl0; + unsigned int usbphytune0; + unsigned int reserved1[2]; + unsigned int hsicphyctrl1; + unsigned int hsicphytune1; + unsigned int reserved2[2]; + unsigned int hsicphyctrl2; + unsigned int hsicphytune2; + unsigned int reserved3[2]; + unsigned int ehcictrl; + unsigned int ohcictrl; + unsigned int usbotgsys; + unsigned int reserved4; + unsigned int usbotgtune; +}; + +/* Switch on the VBUS power. */ +int board_usb_vbus_init(void); + +#endif /* __ASM_ARM_ARCH_EXYNOS5_EHCI_S5P_H__ */ diff --git a/src/include/cpu/samsung/exynos5250/exynos-cpufreq.h b/src/include/cpu/samsung/exynos5250/exynos-cpufreq.h new file mode 100644 index 0000000..1c28e77 --- /dev/null +++ b/src/include/cpu/samsung/exynos5250/exynos-cpufreq.h @@ -0,0 +1,54 @@ +/* + * Copyright (c) 2012 Samsung Electronics Co., Ltd. + * http://www.samsung.com + * + * EXYNOS - CPU frequency scaling support + * + * 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 version 2 as + * published by the Free Software Foundation. + * 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 various levels of ARM frequency */ +enum cpufreq_level { + CPU_FREQ_L200, /* 200 MHz */ + CPU_FREQ_L300, /* 300 MHz */ + CPU_FREQ_L400, /* 400 MHz */ + CPU_FREQ_L500, /* 500 MHz */ + CPU_FREQ_L600, /* 600 MHz */ + CPU_FREQ_L700, /* 700 MHz */ + CPU_FREQ_L800, /* 800 MHz */ + CPU_FREQ_L900, /* 900 MHz */ + CPU_FREQ_L1000, /* 1000 MHz */ + CPU_FREQ_L1100, /* 1100 MHz */ + CPU_FREQ_L1200, /* 1200 MHz */ + CPU_FREQ_L1300, /* 1300 MHz */ + CPU_FREQ_L1400, /* 1400 MHz */ + CPU_FREQ_L1500, /* 1500 MHz */ + CPU_FREQ_L1600, /* 1600 MHz */ + CPU_FREQ_L1700, /* 1700 MHz */ + CPU_FREQ_LCOUNT, +}; + +/* + * Initialize ARM frequency scaling + * + * @param blob FDT blob + * @return int value, 0 for success + */ +int exynos5250_cpufreq_init(const void *blob); + +/* + * Switch ARM frequency to new level + * + * @param new_freq_level enum cpufreq_level, states new frequency + * @return int value, 0 for success + */ +int exynos5250_set_frequency(enum cpufreq_level new_freq_level); diff --git a/src/include/cpu/samsung/exynos5250/exynos-tmu.h b/src/include/cpu/samsung/exynos5250/exynos-tmu.h new file mode 100644 index 0000000..ad9e394 --- /dev/null +++ b/src/include/cpu/samsung/exynos5250/exynos-tmu.h @@ -0,0 +1,82 @@ +/* + * Copyright (c) 2012 Samsung Electronics Co., Ltd. + * http://www.samsung.com + * Akshay Saraswat Akshay.s@samsung.com + * + * EXYNOS - Thermal Management Unit + * + * 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 version 2 as + * published by the Free Software Foundation. + * 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_ARCH_THERMAL_H +#define __ASM_ARCH_THERMAL_H + +struct tmu_reg { + unsigned triminfo; + unsigned rsvd1; + unsigned rsvd2; + unsigned rsvd3; + unsigned rsvd4; + unsigned triminfo_control; + unsigned rsvd5; + unsigned rsvd6; + unsigned tmu_control; + unsigned rsvd7; + unsigned tmu_status; + unsigned sampling_internal; + unsigned counter_value0; + unsigned counter_value1; + unsigned rsvd8; + unsigned rsvd9; + unsigned current_temp; + unsigned rsvd10; + unsigned rsvd11; + unsigned rsvd12; + unsigned threshold_temp_rise; + unsigned threshold_temp_fall; + unsigned rsvd13; + unsigned rsvd14; + unsigned past_temp3_0; + unsigned past_temp7_4; + unsigned past_temp11_8; + unsigned past_temp15_12; + unsigned inten; + unsigned intstat; + unsigned intclear; + unsigned rsvd15; + unsigned emul_con; +}; + +enum tmu_status_t { + TMU_STATUS_INIT = 0, + TMU_STATUS_NORMAL, + TMU_STATUS_WARNING, + TMU_STATUS_TRIPPED, +}; + +/* + * Monitors status of the TMU device and exynos temperature + * + * @param temp pointer to the current temperature value + * @return enum tmu_status_t value, code indicating event to execute + * and -1 on error + */ +enum tmu_status_t tmu_monitor(int *temp); + +/* + * Initialize TMU device + * + * @param blob FDT blob + * @return int value, 0 for success + */ +int tmu_init(const void *blob); +#endif diff --git a/src/include/cpu/samsung/exynos5250/fet.h b/src/include/cpu/samsung/exynos5250/fet.h new file mode 100644 index 0000000..e76bcbf --- /dev/null +++ b/src/include/cpu/samsung/exynos5250/fet.h @@ -0,0 +1,25 @@ +/* + * 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. + */ + +#ifndef __ASM_ARM_ARCH_EXYNOS5_FET_H +#define __ASM_ARM_ARCH_EXYNOS5_FET_H + +/* The FET IDs for TPS65090 PMU chip. */ +enum { + FET_ID_BL = 1 + FET_ID_VIDEO, + FET_ID_WWAN, + FET_ID_SDCARD, + FET_ID_CAMOUT, + FET_ID_LCD, + FET_ID_TS +}; + +#endif diff --git a/src/include/cpu/samsung/exynos5250/fimd.h b/src/include/cpu/samsung/exynos5250/fimd.h new file mode 100644 index 0000000..a46ad5a --- /dev/null +++ b/src/include/cpu/samsung/exynos5250/fimd.h @@ -0,0 +1,137 @@ +/* + * (C) Copyright 2012 Samsung Electronics + * Register map for Exynos5 FIMD + * + * 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 __EXYNOS5_FIMD_H__ +#define __EXYNOS5_FIMD_H__ + +/* FIMD register map */ +struct exynos5_fimd { + /* This is an incomplete list. Add registers as and when required */ + unsigned int vidcon0; + unsigned char res1[0x1c]; + unsigned int wincon0; + unsigned int wincon1; + unsigned int wincon2; + unsigned int wincon3; + unsigned int wincon4; + unsigned int shadowcon; + unsigned char res2[0x8]; + unsigned int vidosd0a; + unsigned int vidosd0b; + unsigned int vidosd0c; + unsigned char res3[0x54]; + unsigned int vidw00add0b0; + unsigned char res4[0x2c]; + unsigned int vidw00add1b0; + unsigned char res5[0x2c]; + unsigned int vidw00add2; + unsigned char res6[0x3c]; + unsigned int w1keycon0; + unsigned int w1keycon1; + unsigned int w2keycon0; + unsigned int w2keycon1; + unsigned int w3keycon0; + unsigned int w3keycon1; + unsigned int w4keycon0; + unsigned int w4keycon1; + unsigned char res7[0x20]; + unsigned int win0map; + unsigned char res8[0xdc]; + unsigned int blendcon; + unsigned char res9[0x18]; + unsigned int dpclkcon; +}; + +#define W0_SHADOW_PROTECT (0x1 << 10) +#define COMPKEY_F 0xffffff +#define ENVID_F_ON (0x1 << 0) +#define ENVID_ON (0x1 << 1) +#define CLKVAL_F 0xb +#define CLKVAL_F_OFFSET 6 + +/* + * Structure containing display panel specific data for FIMD + */ +struct exynos5_fimd_panel { + unsigned int is_dp:1; /* Display Panel interface is eDP */ + unsigned int is_mipi:1; /* Display Panel interface is MIPI */ + unsigned int fixvclk:2; /* VCLK hold scheme at data underflow */ + + /* + * Polarity of the VCLK active edge + * 0-falling + * 1-rising + */ + unsigned int ivclk:1; + unsigned int clkval_f; /* Divider to create pixel clock */ + + unsigned int upper_margin; /* Vertical Backporch */ + unsigned int lower_margin; /* Vertical frontporch */ + unsigned int vsync; /* Vertical Sync Pulse Width */ + unsigned int left_margin; /* Horizantal Backporch */ + unsigned int right_margin; /* Horizontal Frontporch */ + unsigned int hsync; /* Horizontal Sync Pulse Width */ + unsigned int xres; /* X Resolution */ + unsigned int yres; /* Y Resopultion */ +}; + +/* LCDIF Register Map */ +struct exynos5_disp_ctrl { + unsigned int vidout_con; + unsigned int vidcon1; + unsigned char res1[0x8]; + unsigned int vidtcon0; + unsigned int vidtcon1; + unsigned int vidtcon2; + unsigned int vidtcon3; + unsigned char res2[0x184]; + unsigned int trigcon; +}; + +#define VCLK_RISING_EDGE (1 << 7) +#define VCLK_RUNNING (1 << 9) + +#define CHANNEL0_EN (1 << 0) + +#define VSYNC_PULSE_WIDTH_VAL 0x3 +#define VSYNC_PULSE_WIDTH_OFFSET 0 +#define V_FRONT_PORCH_VAL 0x3 +#define V_FRONT_PORCH_OFFSET 8 +#define V_BACK_PORCH_VAL 0x3 +#define V_BACK_PORCH_OFFSET 16 + +#define HSYNC_PULSE_WIDTH_VAL 0x3 +#define HSYNC_PULSE_WIDTH_OFFSET 0 +#define H_FRONT_PORCH_VAL 0x3 +#define H_FRONT_PORCH_OFFSET 8 +#define H_BACK_PORCH_VAL 0x3 +#define H_BACK_PORCH_OFFSET 16 + +#define HOZVAL_OFFSET 0 +#define LINEVAL_OFFSET 11 + +#define BPPMODE_F_RGB_16BIT_565 0x5 +#define BPPMODE_F_OFFSET 2 +#define ENWIN_F_ENABLE (1 << 0) +#define HALF_WORD_SWAP_EN (1 << 16) + +#define OSD_RIGHTBOTX_F_OFFSET 11 +#define OSD_RIGHTBOTY_F_OFFSET 0 +#endif diff --git a/src/include/cpu/samsung/exynos5250/gpio.h b/src/include/cpu/samsung/exynos5250/gpio.h new file mode 100644 index 0000000..b45cf5c --- /dev/null +++ b/src/include/cpu/samsung/exynos5250/gpio.h @@ -0,0 +1,482 @@ +/* + * (C) Copyright 2010 Samsung Electronics + * Minkyu Kang mk7.kang@samsung.com + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +#ifndef EXYNOS5250_GPIO_H_ +#define EXYNOS5250_GPIO_H_ + +#include <cpu/samsung/exynos-common/gpio.h> + +struct exynos5_gpio_part1 { + struct s5p_gpio_bank a0; + struct s5p_gpio_bank a1; + struct s5p_gpio_bank a2; + struct s5p_gpio_bank b0; + struct s5p_gpio_bank b1; + struct s5p_gpio_bank b2; + struct s5p_gpio_bank b3; + struct s5p_gpio_bank c0; + struct s5p_gpio_bank c1; + struct s5p_gpio_bank c2; + struct s5p_gpio_bank c3; + struct s5p_gpio_bank d0; + struct s5p_gpio_bank d1; + struct s5p_gpio_bank y0; + struct s5p_gpio_bank y1; + struct s5p_gpio_bank y2; + struct s5p_gpio_bank y3; + struct s5p_gpio_bank y4; + struct s5p_gpio_bank y5; + struct s5p_gpio_bank y6; +}; + +struct exynos5_gpio_part2 { + struct s5p_gpio_bank x0; + struct s5p_gpio_bank x1; + struct s5p_gpio_bank x2; + struct s5p_gpio_bank x3; +}; + +struct exynos5_gpio_part3 { + struct s5p_gpio_bank e0; + struct s5p_gpio_bank e1; + struct s5p_gpio_bank f0; + struct s5p_gpio_bank f1; + struct s5p_gpio_bank g0; + struct s5p_gpio_bank g1; + struct s5p_gpio_bank g2; + struct s5p_gpio_bank h0; + struct s5p_gpio_bank h1; +}; + +struct exynos5_gpio_part4 { + struct s5p_gpio_bank v0; + struct s5p_gpio_bank v1; + struct s5p_gpio_bank v2; + struct s5p_gpio_bank v3; +}; + +struct exynos5_gpio_part5 { + struct s5p_gpio_bank v4; +}; + +struct exynos5_gpio_part6 { + struct s5p_gpio_bank z; +}; + +enum { + /* GPIO banks are split into this many parts */ + EXYNOS_GPIO_NUM_PARTS = 6 +}; + +/* A list of valid GPIO numbers for the asm-generic/gpio.h interface */ +enum exynos5_gpio_pin { + /* GPIO_PART1_STARTS */ + GPIO_A00, + GPIO_A01, + GPIO_A02, + GPIO_A03, + GPIO_A04, + GPIO_A05, + GPIO_A06, + GPIO_A07, + GPIO_A10, + GPIO_A11, + GPIO_A12, + GPIO_A13, + GPIO_A14, + GPIO_A15, + GPIO_A16, + GPIO_A17, + GPIO_A20, + GPIO_A21, + GPIO_A22, + GPIO_A23, + GPIO_A24, + GPIO_A25, + GPIO_A26, + GPIO_A27, + GPIO_B00, /* 0x18 */ + GPIO_B01, + GPIO_B02, + GPIO_B03, + GPIO_B04, + GPIO_B05, + GPIO_B06, + GPIO_B07, + GPIO_B10, + GPIO_B11, + GPIO_B12, + GPIO_B13, + GPIO_B14, + GPIO_B15, + GPIO_B16, + GPIO_B17, + GPIO_B20, + GPIO_B21, + GPIO_B22, + GPIO_B23, + GPIO_B24, + GPIO_B25, + GPIO_B26, + GPIO_B27, + GPIO_B30, + GPIO_B31, + GPIO_B32, + GPIO_B33, + GPIO_B34, + GPIO_B35, + GPIO_B36, + GPIO_B37, + GPIO_C00, /* 0x38 */ + GPIO_C01, + GPIO_C02, + GPIO_C03, + GPIO_C04, + GPIO_C05, + GPIO_C06, + GPIO_C07, + GPIO_C10, + GPIO_C11, + GPIO_C12, + GPIO_C13, + GPIO_C14, + GPIO_C15, + GPIO_C16, + GPIO_C17, + GPIO_C20, + GPIO_C21, + GPIO_C22, + GPIO_C23, + GPIO_C24, + GPIO_C25, + GPIO_C26, + GPIO_C27, + GPIO_C30, + GPIO_C31, + GPIO_C32, + GPIO_C33, + GPIO_C34, + GPIO_C35, + GPIO_C36, + GPIO_C37, + GPIO_D00, /* 0x58 */ + GPIO_D01, + GPIO_D02, + GPIO_D03, + GPIO_D04, + GPIO_D05, + GPIO_D06, + GPIO_D07, + GPIO_D10, + GPIO_D11, + GPIO_D12, + GPIO_D13, + GPIO_D14, + GPIO_D15, + GPIO_D16, + GPIO_D17, + GPIO_Y00, /* 0x68 */ + GPIO_Y01, + GPIO_Y02, + GPIO_Y03, + GPIO_Y04, + GPIO_Y05, + GPIO_Y06, + GPIO_Y07, + GPIO_Y10, + GPIO_Y11, + GPIO_Y12, + GPIO_Y13, + GPIO_Y14, + GPIO_Y15, + GPIO_Y16, + GPIO_Y17, + GPIO_Y20, + GPIO_Y21, + GPIO_Y22, + GPIO_Y23, + GPIO_Y24, + GPIO_Y25, + GPIO_Y26, + GPIO_Y27, + GPIO_Y30, + GPIO_Y31, + GPIO_Y32, + GPIO_Y33, + GPIO_Y34, + GPIO_Y35, + GPIO_Y36, + GPIO_Y37, + GPIO_Y40, + GPIO_Y41, + GPIO_Y42, + GPIO_Y43, + GPIO_Y44, + GPIO_Y45, + GPIO_Y46, + GPIO_Y47, + GPIO_Y50, + GPIO_Y51, + GPIO_Y52, + GPIO_Y53, + GPIO_Y54, + GPIO_Y55, + GPIO_Y56, + GPIO_Y57, + GPIO_Y60, + GPIO_Y61, + GPIO_Y62, + GPIO_Y63, + GPIO_Y64, + GPIO_Y65, + GPIO_Y66, + GPIO_Y67, + + /* GPIO_PART2_STARTS */ + GPIO_MAX_PORT_PART_1, + GPIO_X00 = GPIO_MAX_PORT_PART_1, /* 0xa0 */ + GPIO_X01, + GPIO_X02, + GPIO_X03, + GPIO_X04, + GPIO_X05, + GPIO_X06, + GPIO_X07, + GPIO_X10, + GPIO_X11, + GPIO_X12, + GPIO_X13, + GPIO_X14, + GPIO_X15, + GPIO_X16, + GPIO_X17, + GPIO_X20, + GPIO_X21, + GPIO_X22, + GPIO_X23, + GPIO_X24, + GPIO_X25, + GPIO_X26, + GPIO_X27, + GPIO_X30, + GPIO_X31, + GPIO_X32, + GPIO_X33, + GPIO_X34, + GPIO_X35, + GPIO_X36, + GPIO_X37, + + /* GPIO_PART3_STARTS */ + GPIO_MAX_PORT_PART_2, + GPIO_E00 = GPIO_MAX_PORT_PART_2, /* 0xc0 */ + GPIO_E01, + GPIO_E02, + GPIO_E03, + GPIO_E04, + GPIO_E05, + GPIO_E06, + GPIO_E07, + GPIO_E10, + GPIO_E11, + GPIO_E12, + GPIO_E13, + GPIO_E14, + GPIO_E15, + GPIO_E16, + GPIO_E17, + GPIO_F00, /* 0xd0 */ + GPIO_F01, + GPIO_F02, + GPIO_F03, + GPIO_F04, + GPIO_F05, + GPIO_F06, + GPIO_F07, + GPIO_F10, + GPIO_F11, + GPIO_F12, + GPIO_F13, + GPIO_F14, + GPIO_F15, + GPIO_F16, + GPIO_F17, + GPIO_G00, + GPIO_G01, + GPIO_G02, + GPIO_G03, + GPIO_G04, + GPIO_G05, + GPIO_G06, + GPIO_G07, + GPIO_G10, + GPIO_G11, + GPIO_G12, + GPIO_G13, + GPIO_G14, + GPIO_G15, + GPIO_G16, + GPIO_G17, + GPIO_G20, + GPIO_G21, + GPIO_G22, + GPIO_G23, + GPIO_G24, + GPIO_G25, + GPIO_G26, + GPIO_G27, + GPIO_H00, + GPIO_H01, + GPIO_H02, + GPIO_H03, + GPIO_H04, + GPIO_H05, + GPIO_H06, + GPIO_H07, + GPIO_H10, + GPIO_H11, + GPIO_H12, + GPIO_H13, + GPIO_H14, + GPIO_H15, + GPIO_H16, + GPIO_H17, + + /* GPIO_PART4_STARTS */ + GPIO_MAX_PORT_PART_3, + GPIO_V00 = GPIO_MAX_PORT_PART_3, + GPIO_V01, + GPIO_V02, + GPIO_V03, + GPIO_V04, + GPIO_V05, + GPIO_V06, + GPIO_V07, + GPIO_V10, + GPIO_V11, + GPIO_V12, + GPIO_V13, + GPIO_V14, + GPIO_V15, + GPIO_V16, + GPIO_V17, + GPIO_V20, + GPIO_V21, + GPIO_V22, + GPIO_V23, + GPIO_V24, + GPIO_V25, + GPIO_V26, + GPIO_V27, + GPIO_V30, + GPIO_V31, + GPIO_V32, + GPIO_V33, + GPIO_V34, + GPIO_V35, + GPIO_V36, + GPIO_V37, + + /* GPIO_PART5_STARTS */ + GPIO_MAX_PORT_PART_4, + GPIO_V40 = GPIO_MAX_PORT_PART_4, + GPIO_V41, + GPIO_V42, + GPIO_V43, + GPIO_V44, + GPIO_V45, + GPIO_V46, + GPIO_V47, + + /* GPIO_PART6_STARTS */ + GPIO_MAX_PORT_PART_5, + GPIO_Z0 = GPIO_MAX_PORT_PART_5, + GPIO_Z1, + GPIO_Z2, + GPIO_Z3, + GPIO_Z4, + GPIO_Z5, + GPIO_Z6, + GPIO_MAX_PORT +}; + +#define gpio_status gpio_info + +/** + * Set GPIO pin configuration. + * + * @param gpio GPIO pin + * @param cfg Either GPIO_INPUT, GPIO_OUTPUT, or GPIO_IRQ + */ +void gpio_cfg_pin(int gpio, int cfg); + +/** + * Set GPIO pull mode. + * + * @param gpio GPIO pin + * @param mode Either GPIO_PULL_DOWN or GPIO_PULL_UP + */ +void gpio_set_pull(int gpio, int mode); + +/** + * Set GPIO drive strength level. + * + * @param gpio GPIO pin + * @param mode Either GPIO_DRV_1X, GPIO_DRV_2X, GPIO_DRV_3X, or GPIO_DRV_4X + */ +void gpio_set_drv(int gpio, int mode); + +/** + * Set GPIO drive rate. + * + * @param gpio GPIO pin + * @param mode Either GPIO_DRV_FAST or GPIO_DRV_SLOW + */ +void gpio_set_rate(int gpio, int mode); + +/* FIXME(dhendrix) use generic arch/gpio.h API instead */ +//int gpio_direction_input(unsigned gpio); +//int gpio_direction_output(unsigned gpio, int value); + +/** + * Decode a list of GPIOs into an integer. + * + * TODO(sjg@chromium.org): This could perhaps become a generic function? + * + * Each GPIO pin can be put into three states using external resistors: + * - pulled up + * - pulled down + * - not connected + * + * Read each GPIO in turn to produce an integer value. The first GPIO + * produces a number 1 * (0 to 2), the second produces 3 * (0 to 2), etc. + * In this way, each GPIO increases the number of possible states by a + * factor of 3. + * + * @param gpio_list List of GPIO numbers to decode + * @param count Number of GPIOs in list + * @return -1 if the value cannot be determined, or any GPIO number is + * invalid. Otherwise returns the calculated value + */ +int gpio_decode_number(unsigned gpio_list[], int count); + +void gpio_info(void); + +#endif /* EXYNOS5250_GPIO_H_ */ diff --git a/src/include/cpu/samsung/exynos5250/i2s-regs.h b/src/include/cpu/samsung/exynos5250/i2s-regs.h new file mode 100644 index 0000000..19267ca --- /dev/null +++ b/src/include/cpu/samsung/exynos5250/i2s-regs.h @@ -0,0 +1,146 @@ +/* + * Copyright (C) 2012 Samsung Electronics + * R. Chandrasekar rcsekar@samsung.com + * + * Taken from the kernel code + * + * 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 __I2S_REGS_H__ +#define __I2S_REGS_H__ + +#define I2SCON 0x0 +#define I2SMOD 0x4 +#define I2SFIC 0x8 +#define I2SPSR 0xc +#define I2STXD 0x10 +#define I2SRXD 0x14 +#define I2SFICS 0x18 +#define I2STXDS 0x1c +#define I2SAHB 0x20 +#define I2SSTR0 0x24 +#define I2SSIZE 0x28 +#define I2STRNCNT 0x2c +#define I2SLVL0ADDR 0x30 +#define I2SLVL1ADDR 0x34 +#define I2SLVL2ADDR 0x38 +#define I2SLVL3ADDR 0x3c + +#define CON_RSTCLR (1 << 31) +#define CON_FRXOFSTATUS (1 << 26) +#define CON_FRXORINTEN (1 << 25) +#define CON_FTXSURSTAT (1 << 24) +#define CON_FTXSURINTEN (1 << 23) +#define CON_TXSDMA_PAUSE (1 << 20) +#define CON_TXSDMA_ACTIVE (1 << 18) + +#define CON_FTXURSTATUS (1 << 17) +#define CON_FTXURINTEN (1 << 16) +#define CON_TXFIFO2_EMPTY (1 << 15) +#define CON_TXFIFO1_EMPTY (1 << 14) +#define CON_TXFIFO2_FULL (1 << 13) +#define CON_TXFIFO1_FULL (1 << 12) + +#define CON_LRINDEX (1 << 11) +#define CON_TXFIFO_EMPTY (1 << 10) +#define CON_RXFIFO_EMPTY (1 << 9) +#define CON_TXFIFO_FULL (1 << 8) +#define CON_RXFIFO_FULL (1 << 7) +#define CON_TXDMA_PAUSE (1 << 6) +#define CON_RXDMA_PAUSE (1 << 5) +#define CON_TXCH_PAUSE (1 << 4) +#define CON_RXCH_PAUSE (1 << 3) +#define CON_TXDMA_ACTIVE (1 << 2) +#define CON_RXDMA_ACTIVE (1 << 1) +#define CON_ACTIVE (1 << 0) + +#define MOD_OPCLK_CDCLK_OUT (0 << 30) +#define MOD_OPCLK_CDCLK_IN (1 << 30) +#define MOD_OPCLK_BCLK_OUT (2 << 30) +#define MOD_OPCLK_PCLK (3 << 30) +#define MOD_OPCLK_MASK (3 << 30) +#define MOD_TXS_IDMA (1 << 28) /* Sec_TXFIFO use I-DMA */ + +#define MOD_BLCS_SHIFT 26 +#define MOD_BLCS_16BIT (0 << MOD_BLCS_SHIFT) +#define MOD_BLCS_8BIT (1 << MOD_BLCS_SHIFT) +#define MOD_BLCS_24BIT (2 << MOD_BLCS_SHIFT) +#define MOD_BLCS_MASK (3 << MOD_BLCS_SHIFT) + +#define MOD_BLCP_SHIFT 24 +#define MOD_BLCP_16BIT (0 << MOD_BLCP_SHIFT) +#define MOD_BLCP_8BIT (1 << MOD_BLCP_SHIFT) +#define MOD_BLCP_24BIT (2 << MOD_BLCP_SHIFT) +#define MOD_BLCP_MASK (3 << MOD_BLCP_SHIFT) + +#define MOD_C2DD_HHALF (1 << 21) /* Discard Higher-half */ +#define MOD_C2DD_LHALF (1 << 20) /* Discard Lower-half */ +#define MOD_C1DD_HHALF (1 << 19) +#define MOD_C1DD_LHALF (1 << 18) +#define MOD_DC2_EN (1 << 17) +#define MOD_DC1_EN (1 << 16) +#define MOD_BLC_16BIT (0 << 13) +#define MOD_BLC_8BIT (1 << 13) +#define MOD_BLC_24BIT (2 << 13) +#define MOD_BLC_MASK (3 << 13) + +#define MOD_IMS_SYSMUX (1 << 10) +#define MOD_SLAVE (1 << 11) +#define MOD_TXONLY (0 << 8) +#define MOD_RXONLY (1 << 8) +#define MOD_TXRX (2 << 8) +#define MOD_MASK (3 << 8) +#define MOD_LR_LLOW (0 << 7) +#define MOD_LR_RLOW (1 << 7) +#define MOD_SDF_IIS (0 << 5) +#define MOD_SDF_MSB (1 << 5) +#define MOD_SDF_LSB (2 << 5) +#define MOD_SDF_MASK (3 << 5) +#define MOD_RCLK_256FS (0 << 3) +#define MOD_RCLK_512FS (1 << 3) +#define MOD_RCLK_384FS (2 << 3) +#define MOD_RCLK_768FS (3 << 3) +#define MOD_RCLK_MASK (3 << 3) +#define MOD_BCLK_32FS (0 << 1) +#define MOD_BCLK_48FS (1 << 1) +#define MOD_BCLK_16FS (2 << 1) +#define MOD_BCLK_24FS (3 << 1) +#define MOD_BCLK_MASK (3 << 1) +#define MOD_8BIT (1 << 0) + +#define MOD_CDCLKCON (1 << 12) + +#define PSR_PSREN (1 << 15) + +#define FIC_TXFLUSH (1 << 15) +#define FIC_RXFLUSH (1 << 7) + +#define AHB_INTENLVL0 (1 << 24) +#define AHB_LVL0INT (1 << 20) +#define AHB_CLRLVL0INT (1 << 16) +#define AHB_DMARLD (1 << 5) +#define AHB_INTMASK (1 << 3) +#define AHB_DMAEN (1 << 0) +#define AHB_LVLINTMASK (0xf << 20) + +#define I2SSIZE_TRNMSK (0xffff) +#define I2SSIZE_SHIFT (16) + +#endif /* __I2S_REGS_H__ */ diff --git a/src/include/cpu/samsung/exynos5250/mmc.h b/src/include/cpu/samsung/exynos5250/mmc.h new file mode 100644 index 0000000..24acbc1 --- /dev/null +++ b/src/include/cpu/samsung/exynos5250/mmc.h @@ -0,0 +1,27 @@ +/* + * (C) Copyright 2012 Samsung Electronics + * Minkyu Kang mk7.kang@samsung.com + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + */ + +#ifndef __ASM_ARM_ARCH_EXYNOS5_MMC_H__ +#define __ASM_ARM_ARCH_EXYNOS5_MMC_H__ + +#include <asm/arch-exynos/mmc.h> + +#endif /* __ASM_ARM_ARCH_EXYNOS5_MMC_H__ */ diff --git a/src/include/cpu/samsung/exynos5250/mshc.h b/src/include/cpu/samsung/exynos5250/mshc.h new file mode 100644 index 0000000..d8e3ad0 --- /dev/null +++ b/src/include/cpu/samsung/exynos5250/mshc.h @@ -0,0 +1,31 @@ +/* + * (C) Copyright 2012 Samsung Electronics + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + */ + +#ifndef __ASM_ARM_ARCH_EXYNOS5_MSHC_H__ +#define __ASM_ARM_ARCH_EXYNOS5_MSHC_H__ + +#include <asm/arch-exynos/mshc.h> + +#define MAX_MSHCI_CLOCK 52000000 /* Max limit for mshc clock is 52MHz */ +#define MIN_MSHCI_CLOCK 400000 /* Lower limit for mshc clock is 400KHz */ +#define COMMAND_TIMEOUT 10000 +#define TIMEOUT_MS 100 + +#endif /* __ASM_ARM_ARCH_EXYNOS5_MSHC_H__ */ diff --git a/src/include/cpu/samsung/exynos5250/periph.h b/src/include/cpu/samsung/exynos5250/periph.h new file mode 100644 index 0000000..e14829e --- /dev/null +++ b/src/include/cpu/samsung/exynos5250/periph.h @@ -0,0 +1,71 @@ +/* + * (C) Copyright 2012 The Chromium Authors + * + * 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 __EXYNOS_PERIPH_H +#define __EXYNOS_PERIPH_H + +/* + * Peripherals requiring clock/pinmux configuration. List will + * grow with support for more devices getting added. + * + * At present the order is arbitrary - we may be able to take advantage + * of some orthogonality later. + */ +enum periph_id { + PERIPH_ID_UART0, + PERIPH_ID_UART1, + PERIPH_ID_UART2, + PERIPH_ID_UART3, + PERIPH_ID_SDMMC0, + PERIPH_ID_SDMMC1, + PERIPH_ID_SDMMC2, + PERIPH_ID_SDMMC3, + + /* TODO: make sequential again when FDT doesn't hardcode. */ + PERIPH_ID_SROMC = 9, + PERIPH_ID_SPI0, + PERIPH_ID_SPI1, + PERIPH_ID_SPI2, + PERIPH_ID_SPI3, + PERIPH_ID_SPI4, + PERIPH_ID_LCD, + PERIPH_ID_BACKLIGHT, + PERIPH_ID_I2C0, + PERIPH_ID_I2C1, + PERIPH_ID_I2C2, + PERIPH_ID_I2C3, + PERIPH_ID_I2C4, + PERIPH_ID_I2C5, + PERIPH_ID_I2C6, + PERIPH_ID_I2C7, + PERIPH_ID_DPHPD, /* eDP hot plug detect */ + PERIPH_ID_PWM0, + PERIPH_ID_PWM1, + PERIPH_ID_PWM2, + PERIPH_ID_PWM3, + PERIPH_ID_PWM4, + PERIPH_ID_I2S1, + PERIPH_ID_SATA, + + PERIPH_ID_COUNT, + PERIPH_ID_NONE = -1, +}; + +#endif diff --git a/src/include/cpu/samsung/exynos5250/pinmux.h b/src/include/cpu/samsung/exynos5250/pinmux.h new file mode 100644 index 0000000..81c0087 --- /dev/null +++ b/src/include/cpu/samsung/exynos5250/pinmux.h @@ -0,0 +1,59 @@ +/* + * Copyright (C) 2012 Samsung Electronics + * + * 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 __EXYNOS_PINMUX_H +#define __EXYNOS_PINMUX_H + +//#include <asm/arch/periph.h> +#include "periph.h" + +enum { + PINMUX_FLAG_NONE = 0x00000000, + + /* Flags for eMMC */ + PINMUX_FLAG_8BIT_MODE = 1 << 0, /* SDMMC 8-bit mode */ + + /* + * Flags for SPI. + */ + PINMUX_FLAG_SLAVE_MODE = 1 << 0, /* Slave mode */ + + /* Flags for SROM controller */ + PINMUX_FLAG_BANK = 3 << 0, /* bank number (0-3) */ + PINMUX_FLAG_16BIT = 1 << 2, /* 16-bit width */ +}; + +/** + * Configures the pinmux for a particular peripheral. + * + * Each gpio can be configured in many different ways (4 bits on exynos) + * such as "input", "output", "special function", "external interrupt" + * etc. This function will configure the peripheral pinmux along with + * pull-up/down and drive strength. + * + * @param peripheral peripheral to be configured + * @param flags configure flags + * @return 0 if ok, -1 on error (e.g. unsupported peripheral) + */ +int exynos_pinmux_config(enum periph_id peripheral, int flags); + +#endif diff --git a/src/include/cpu/samsung/exynos5250/power.h b/src/include/cpu/samsung/exynos5250/power.h new file mode 100644 index 0000000..59a0257 --- /dev/null +++ b/src/include/cpu/samsung/exynos5250/power.h @@ -0,0 +1,89 @@ +/* + * (C) Copyright 2012 Samsung Electronics + * Register map for Exynos5 PMU + * + * 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 __EXYNOS5_POWER_H__ +#define __EXYNOS5_POWER_H__ + +#define MIPI_PHY1_CONTROL_ENABLE (1 << 0) +#define MIPI_PHY1_CONTROL_M_RESETN (1 << 2) + +#define POWER_USB_HOST_PHY_CTRL_EN (1 << 0) +#define POWER_PS_HOLD_CONTROL_DATA_HIGH (1 << 8) +#define POWER_ENABLE_HW_TRIP (1UL << 31) + +#define DPTX_PHY_ENABLE (1 << 0) + +/* PMU_DEBUG bits [12:8] = 0x1000 selects XXTI clock source */ +#define PMU_DEBUG_XXTI 0x1000 +/* Mask bit[12:8] for xxti clock selection */ +#define PMU_DEBUG_CLKOUT_SEL_MASK 0x1f00 + +/* Power Management Unit register map */ +struct exynos5_power { + /* Add registers as and when required */ + uint8_t reserved1[0x0400]; + uint32_t sw_reset; /* 0x0400 */ + uint8_t reserved2[0x0304]; + uint32_t usb_host_phy_ctrl; /* 0x0708 */ + uint8_t reserved3[0x8]; + uint32_t mipi_phy1_control; /* 0x0714 */ + uint8_t reserved4[0x8]; + uint32_t dptx_phy_control; /* 0x0720 */ + uint8_t reserved5[0xdc]; + uint32_t inform0; /* 0x0800 */ + uint32_t inform1; /* 0x0804 */ + uint8_t reserved6[0x1f8]; + uint32_t pmu_debug; /* 0x0A00*/ + uint8_t reserved7[0x2908]; + uint32_t ps_hold_ctrl; /* 0x330c */ +} __attribute__ ((__packed__)); + +/** + * Perform a software reset. + */ +void power_reset(void); + +/** + * Power off the system; it should never return. + */ +void power_shutdown(void); + +/* Enable DPTX PHY */ +void power_enable_dp_phy(void); + +void power_enable_usb_phy(void); +void power_disable_usb_phy(void); + +/* Enable HW thermal trip with PS_HOLD_CONTROL register ENABLE_HW_TRIP bit */ +void power_enable_hw_thermal_trip(void); + +/* Initialize the pmic voltages to power up the system */ +int power_init(void); + +/* Read the reset status. */ +uint32_t power_read_reset_status(void); + +/* Read the resume function and call it. */ +void power_exit_wakeup(void); + +/* pmu debug is used for xclkout, enable xclkout with source as XXTI */ +void power_enable_xclkout(void); + +#endif diff --git a/src/include/cpu/samsung/exynos5250/pwm.h b/src/include/cpu/samsung/exynos5250/pwm.h new file mode 100644 index 0000000..e7ae208 --- /dev/null +++ b/src/include/cpu/samsung/exynos5250/pwm.h @@ -0,0 +1,27 @@ +/* + * (C) Copyright 2012 Samsung Electronics + * Minkyu Kang mk7.kang@samsung.com + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + */ + +#ifndef __ASM_ARM_ARCH_EXYNOS5_PWM_H__ +#define __ASM_ARM_ARCH_EXYNOS5_PWM_H__ + +#include <asm/arch-exynos/pwm.h> + +#endif /* __ASM_ARM_ARCH_EXYNOS5_PWM_H__ */ diff --git a/src/include/cpu/samsung/exynos5250/s5p-dp.h b/src/include/cpu/samsung/exynos5250/s5p-dp.h new file mode 100644 index 0000000..5322383 --- /dev/null +++ b/src/include/cpu/samsung/exynos5250/s5p-dp.h @@ -0,0 +1,513 @@ +/* + * (C) Copyright 2012 Samsung Electronics + * Register map for Exynos5 DP + * + * 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 __EXYNOS5_DP_H__ +#define __EXYNOS5_DP_H__ + +/* DSIM register map */ +struct exynos5_dp { + unsigned char res1[0x10]; + unsigned int dp_tx_version; + unsigned int dp_tx_sw_reset; + unsigned int func_en_1; + unsigned int func_en_2; + unsigned int video_ctl_1; + unsigned int video_ctl_2; + unsigned int video_ctl_3; + unsigned int video_ctl_4; + unsigned int clr_blue_cb; + unsigned int clr_green_y; + unsigned int clr_red_cr; + unsigned int video_ctl_8; + unsigned char res2[0x4]; + unsigned int video_ctl_10; + unsigned int total_line_l; + unsigned int total_line_h; + unsigned int active_line_l; + unsigned int active_line_h; + unsigned int v_f_porch; + unsigned int vsync; + unsigned int v_b_porch; + unsigned int total_pixel_l; + unsigned int total_pixel_h; + unsigned int active_pixel_l; + unsigned int active_pixel_h; + unsigned int h_f_porch_l; + unsigned int h_f_porch_h; + unsigned int hsync_l; + unsigned int hysnc_h; + unsigned int h_b_porch_l; + unsigned int h_b_porch_h; + unsigned int vid_status; + unsigned int total_line_sta_l; + unsigned int total_line_sta_h; + unsigned int active_line_sta_l; + unsigned int active_line_sta_h; + unsigned int v_f_porch_sta; + unsigned int vsync_sta; + unsigned int v_b_porch_sta; + unsigned int total_pixel_sta_l; + unsigned int total_pixel_sta_h; + unsigned int active_pixel_sta_l; + unsigned int active_pixel_sta_h; + unsigned int h_f_porch_sta_l; + unsigned int h_f_porch_sta_h; + unsigned int hsync_sta_l; + unsigned int hsync_sta_h; + unsigned int h_b_porch_sta_l; + unsigned int h_b_porch__sta_h; + unsigned char res3[0x288]; + unsigned int lane_map; + unsigned char res4[0x10]; + unsigned int analog_ctl_1; + unsigned int analog_ctl_2; + unsigned int analog_ctl_3; + unsigned int pll_filter_ctl_1; + unsigned int tx_amp_tuning_ctl; + unsigned char res5[0xc]; + unsigned int aux_hw_retry_ctl; + unsigned char res6[0x2c]; + unsigned int int_state; + unsigned int common_int_sta_1; + unsigned int common_int_sta_2; + unsigned int common_int_sta_3; + unsigned int common_int_sta_4; + unsigned char res7[0x8]; + unsigned int dp_int_sta; + unsigned int common_int_mask_1; + unsigned int common_int_mask_2; + unsigned int common_int_mask_3; + unsigned int common_int_mask_4; + unsigned char res8[0x08]; + unsigned int int_sta_mask; + unsigned int int_ctl; + unsigned char res9[0x200]; + unsigned int sys_ctl_1; + unsigned int sys_ctl_2; + unsigned int sys_ctl_3; + unsigned int sys_ctl_4; + unsigned int dp_vid_ctl; + unsigned char res10[0x2c]; + unsigned int pkt_send_ctl; + unsigned char res11[0x4]; + unsigned int dp_hdcp_ctl; + unsigned char res12[0x34]; + unsigned int link_bw_set; + unsigned int lane_count_set; + unsigned int dp_training_ptn_set; + unsigned int ln0_link_trn_ctl; + unsigned int ln1_link_trn_ctl; + unsigned int ln2_link_trn_ctl; + unsigned int ln3_link_trn_ctl; + unsigned int dp_dn_spread; + unsigned int dp_hw_link_training; + unsigned char res13[0x1c]; + unsigned int dp_debug_ctl; + unsigned int dp_hpd_deglitch_l; + unsigned int dp_hpd_deglitch_h; + unsigned char res14[0x14]; + unsigned int dp_link_debug_ctl; + unsigned char res15[0x1c]; + unsigned int m_vid_0; + unsigned int m_vid_1; + unsigned int m_vid_2; + unsigned int n_vid_0; + unsigned int n_vid_1; + unsigned int n_vid_2; + unsigned int m_vid_mon; + unsigned int dp_pll_ctl; + unsigned int dp_phy_pd; + unsigned int dp_phy_test; + unsigned char res16[0x8]; + unsigned int dp_video_fifo_thrd; + unsigned char res17[0x8]; + unsigned int dp_audio_margin; + unsigned int dp_dn_spread_ctl_1; + unsigned int dp_dn_spread_ctl_2; + unsigned char res18[0x18]; + unsigned int dp_m_cal_ctl; + unsigned int m_vid_gen_filter_th; + unsigned char res19[0x14]; + unsigned int m_aud_gen_filter_th; + unsigned int aux_ch_sta; + unsigned int aux_err_num; + unsigned int aux_ch_defer_dtl; + unsigned int aux_rx_comm; + unsigned int buf_data_ctl; + unsigned int aux_ch_ctl_1; + unsigned int aux_addr_7_0; + unsigned int aux_addr_15_8; + unsigned int aux_addr_19_16; + unsigned int aux_ch_ctl_2; + unsigned char res20[0x18]; + unsigned int buf_data_0; + unsigned char res21[0x3c]; + unsigned int soc_general_ctl; +}; +/* DP_TX_SW_RESET */ +#define RESET_DP_TX (1 << 0) + +/* DP_FUNC_EN_1 */ +#define MASTER_VID_FUNC_EN_N (1 << 7) +#define SLAVE_VID_FUNC_EN_N (1 << 5) +#define AUD_FIFO_FUNC_EN_N (1 << 4) +#define AUD_FUNC_EN_N (1 << 3) +#define HDCP_FUNC_EN_N (1 << 2) +#define CRC_FUNC_EN_N (1 << 1) +#define SW_FUNC_EN_N (1 << 0) + +/* DP_FUNC_EN_2 */ +#define SSC_FUNC_EN_N (1 << 7) +#define AUX_FUNC_EN_N (1 << 2) +#define SERDES_FIFO_FUNC_EN_N (1 << 1) +#define LS_CLK_DOMAIN_FUNC_EN_N (1 << 0) + +/* DP_VIDEO_CTL_1 */ +#define VIDEO_EN (1 << 7) +#define HDCP_VIDEO_MUTE (1 << 6) + +/* DP_VIDEO_CTL_1 */ +#define IN_D_RANGE_MASK (1 << 7) +#define IN_D_RANGE_SHIFT (7) +#define IN_D_RANGE_CEA (1 << 7) +#define IN_D_RANGE_VESA (0 << 7) +#define IN_BPC_MASK (7 << 4) +#define IN_BPC_SHIFT (4) +#define IN_BPC_12_BITS (3 << 4) +#define IN_BPC_10_BITS (2 << 4) +#define IN_BPC_8_BITS (1 << 4) +#define IN_BPC_6_BITS (0 << 4) +#define IN_COLOR_F_MASK (3 << 0) +#define IN_COLOR_F_SHIFT (0) +#define IN_COLOR_F_YCBCR444 (2 << 0) +#define IN_COLOR_F_YCBCR422 (1 << 0) +#define IN_COLOR_F_RGB (0 << 0) + +/* DP_VIDEO_CTL_3 */ +#define IN_YC_COEFFI_MASK (1 << 7) +#define IN_YC_COEFFI_SHIFT (7) +#define IN_YC_COEFFI_ITU709 (1 << 7) +#define IN_YC_COEFFI_ITU601 (0 << 7) +#define VID_CHK_UPDATE_TYPE_MASK (1 << 4) +#define VID_CHK_UPDATE_TYPE_SHIFT (4) +#define VID_CHK_UPDATE_TYPE_1 (1 << 4) +#define VID_CHK_UPDATE_TYPE_0 (0 << 4) + +/* DP_VIDEO_CTL_10 */ +#define FORMAT_SEL (1 << 4) +#define INTERACE_SCAN_CFG (1 << 2) +#define VSYNC_POLARITY_CFG (1 << 1) +#define HSYNC_POLARITY_CFG (1 << 0) + +/* DP_LANE_MAP */ +#define LANE3_MAP_LOGIC_LANE_0 (0 << 6) +#define LANE3_MAP_LOGIC_LANE_1 (1 << 6) +#define LANE3_MAP_LOGIC_LANE_2 (2 << 6) +#define LANE3_MAP_LOGIC_LANE_3 (3 << 6) +#define LANE2_MAP_LOGIC_LANE_0 (0 << 4) +#define LANE2_MAP_LOGIC_LANE_1 (1 << 4) +#define LANE2_MAP_LOGIC_LANE_2 (2 << 4) +#define LANE2_MAP_LOGIC_LANE_3 (3 << 4) +#define LANE1_MAP_LOGIC_LANE_0 (0 << 2) +#define LANE1_MAP_LOGIC_LANE_1 (1 << 2) +#define LANE1_MAP_LOGIC_LANE_2 (2 << 2) +#define LANE1_MAP_LOGIC_LANE_3 (3 << 2) +#define LANE0_MAP_LOGIC_LANE_0 (0 << 0) +#define LANE0_MAP_LOGIC_LANE_1 (1 << 0) +#define LANE0_MAP_LOGIC_LANE_2 (2 << 0) +#define LANE0_MAP_LOGIC_LANE_3 (3 << 0) + +/* DP_AUX_HW_RETRY_CTL */ +#define AUX_BIT_PERIOD_SHIFT 8 +#define AUX_BIT_PERIOD_MASK 7 + +#define AUX_HW_RETRY_INTERVAL_SHIFT 3 +#define AUX_HW_RETRY_INTERVAL_600_US 0 +#define AUX_HW_RETRY_INTERVAL_800_US 1 +#define AUX_HW_RETRY_INTERVAL_1000_US 2 +#define AUX_HW_RETRY_INTERVAL_1800_US 3 +#define AUX_HW_RETRY_COUNT_SHIFT 0 +#define AUX_HW_RETRY_COUNT_MASK 7 + +/* DP_COMMON_INT_STA_1 */ +#define VSYNC_DET (1 << 7) +#define PLL_LOCK_CHG (1 << 6) +#define SPDIF_ERR (1 << 5) +#define SPDIF_UNSTBL (1 << 4) +#define VID_FORMAT_CHG (1 << 3) +#define AUD_CLK_CHG (1 << 2) +#define VID_CLK_CHG (1 << 1) +#define SW_INT (1 << 0) + +/* DP_COMMON_INT_STA_2 */ +#define ENC_EN_CHG (1 << 6) +#define HW_BKSV_RDY (1 << 3) +#define HW_SHA_DONE (1 << 2) +#define HW_AUTH_STATE_CHG (1 << 1) +#define HW_AUTH_DONE (1 << 0) + +/* DP_COMMON_INT_STA_3 */ +#define AFIFO_UNDER (1 << 7) +#define AFIFO_OVER (1 << 6) +#define R0_CHK_FLAG (1 << 5) + +/* DP_COMMON_INT_STA_4 */ +#define PSR_ACTIVE (1 << 7) +#define PSR_INACTIVE (1 << 6) +#define SPDIF_BI_PHASE_ERR (1 << 5) +#define HOTPLUG_CHG (1 << 2) +#define HPD_LOST (1 << 1) +#define PLUG (1 << 0) + +/* DP_INT_STA */ +#define INT_HPD (1 << 6) +#define HW_TRAINING_FINISH (1 << 5) +#define RPLY_RECEIV (1 << 1) +#define AUX_ERR (1 << 0) + +/* DP_INT_CTL */ +#define INT_POL0 (1 << 0) +#define INT_POL1 (1 << 1) +#define SOFT_INT_CTRL (1 << 2) + +/* DP_SYS_CTL_1 */ +#define DET_STA (1 << 2) +#define FORCE_DET (1 << 1) +#define DET_CTRL (1 << 0) + +/* DP_SYS_CTL_2 */ +#define CHA_CRI_SHIFT 4 +#define CHA_CRI_MASK 0xf +#define CHA_STA (1 << 2) +#define FORCE_CHA (1 << 1) +#define CHA_CTRL (1 << 0) + +/* DP_SYS_CTL_3 */ +#define HPD_STATUS (1 << 6) +#define F_HPD (1 << 5) +#define HPD_CTRL (1 << 4) +#define HDCP_RDY (1 << 3) +#define STRM_VALID (1 << 2) +#define F_VALID (1 << 1) +#define VALID_CTRL (1 << 0) + +/* DP_SYS_CTL_4 */ +#define FIX_M_AUD (1 << 4) +#define ENHANCED (1 << 3) +#define FIX_M_VID (1 << 2) +#define M_VID_UPDATE_CTRL (3 << 0) + +/* DP_TRAINING_PTN_SET */ +#define SCRAMBLER_TYPE (1 << 9) +#define HW_LINK_TRAINING_PATTERN (1 << 8) +#define SCRAMBLING_DISABLE (1 << 5) +#define SCRAMBLING_ENABLE (0 << 5) +#define LINK_QUAL_PATTERN_SET_MASK (3 << 2) +#define LINK_QUAL_PATTERN_SET_PRBS7 (3 << 2) +#define LINK_QUAL_PATTERN_SET_D10_2 (1 << 2) +#define LINK_QUAL_PATTERN_SET_DISABLE (0 << 2) +#define SW_TRAINING_PATTERN_SET_MASK (3 << 0) +#define SW_TRAINING_PATTERN_SET_PTN2 (2 << 0) +#define SW_TRAINING_PATTERN_SET_PTN1 (1 << 0) +#define SW_TRAINING_PATTERN_SET_NORMAL (0 << 0) + +/* DP_LN0_LINK_TRAINING_CTL */ +#define PRE_EMPHASIS_SET_SHIFT (3) + +/* DP_DEBUG_CTL */ +#define PLL_LOCK (1 << 4) +#define F_PLL_LOCK (1 << 3) +#define PLL_LOCK_CTRL (1 << 2) +#define PN_INV (1 << 0) + +/* DP_M_VID */ +#define M_VID_0_VALUE_SHIFT 0 +#define M_VID_1_VALUE_SHIFT 8 +#define M_VID_2_VALUE_SHIFT 16 + +/* DP_M_VID */ +#define N_VID_0_VALUE_SHIFT 0 +#define N_VID_1_VALUE_SHIFT 8 +#define N_VID_2_VALUE_SHIFT 16 + +/* DP_PLL_CTL */ +#define DP_PLL_PD (1 << 7) +#define DP_PLL_RESET (1 << 6) +#define DP_PLL_LOOP_BIT_DEFAULT (1 << 4) +#define DP_PLL_REF_BIT_1_1250V (5 << 0) +#define DP_PLL_REF_BIT_1_2500V (7 << 0) + +/* DP_PHY_PD */ +#define DP_PHY_PD (1 << 5) +#define AUX_PD (1 << 4) +#define CH3_PD (1 << 3) +#define CH2_PD (1 << 2) +#define CH1_PD (1 << 1) +#define CH0_PD (1 << 0) + +/* DP_PHY_TEST */ +#define MACRO_RST (1 << 5) +#define CH1_TEST (1 << 1) +#define CH0_TEST (1 << 0) + +/* DP_AUX_CH_STA */ +#define AUX_BUSY (1 << 4) +#define AUX_STATUS_MASK (0xf << 0) + +/* DP_AUX_CH_DEFER_CTL */ +#define DEFER_CTRL_EN (1 << 7) +#define DEFER_COUNT_SHIFT 0 +#define DEFER_COUNT_MASK 0x7f + +/* DP_AUX_RX_COMM */ +#define AUX_RX_COMM_I2C_DEFER (2 << 2) +#define AUX_RX_COMM_AUX_DEFER (2 << 0) + +/* DP_BUFFER_DATA_CTL */ +#define BUF_CLR (1 << 7) + +/* Maximum number of tries for Aux Transaction */ +#define MAX_AUX_RETRY_COUNT 10 + +/* DP_AUX_CH_CTL_1 */ +#define AUX_LENGTH_SHIFT 4 +#define AUX_LENGTH_MASK 0xf + +#define AUX_TX_COMM_MASK (0xf << 0) +#define AUX_TX_COMM_DP_TRANSACTION (1 << 3) +#define AUX_TX_COMM_I2C_TRANSACTION (0 << 3) +#define AUX_TX_COMM_MOT (1 << 2) +#define AUX_TX_COMM_WRITE (0 << 0) +#define AUX_TX_COMM_READ (1 << 0) + +/* DP_AUX_ADDR_7_0 */ +#define AUX_ADDR_7_0_SHIFT 0 +#define AUX_ADDR_7_0_MASK 0xff + +/* DP_AUX_ADDR_15_8 */ +#define AUX_ADDR_15_8_SHIFT 8 +#define AUX_ADDR_15_8_MASK 0xff + +/* DP_AUX_ADDR_19_16 */ +#define AUX_ADDR_19_16_SHIFT 16 +#define AUX_ADDR_19_16_MASK 0x0f + +/* DP_AUX_CH_CTL_2 */ +#define ADDR_ONLY (1 << 1) +#define AUX_EN (1 << 0) + +/* DP_SOC_GENERAL_CTL */ +#define AUDIO_MODE_SPDIF_MODE (1 << 8) +#define AUDIO_MODE_MASTER_MODE (0 << 8) +#define MASTER_VIDEO_INTERLACE_EN (1 << 4) +#define VIDEO_MASTER_CLK_SEL (1 << 2) +#define VIDEO_MASTER_MODE_EN (1 << 1) +#define VIDEO_MODE_MASK (1 << 0) +#define VIDEO_MODE_SLAVE_MODE (1 << 0) +#define VIDEO_MODE_MASTER_MODE (0 << 0) + +#define HW_TRAINING_ERROR_CODE (7<<4) +#define HW_TRAINING_EN (1<<0) + +/* I2C EDID Chip ID, Slave Address */ +#define I2C_EDID_DEVICE_ADDR 0x50 +#define I2C_E_EDID_DEVICE_ADDR 0x30 + +#define EDID_BLOCK_LENGTH 0x80 +#define EDID_HEADER_PATTERN 0x00 +#define EDID_EXTENSION_FLAG 0x7e +#define EDID_CHECKSUM 0x7f + +/* Definition for DPCD Register */ +#define DPCD_ADDR_DPCD_REV 0x0000 +#define DPCD_ADDR_MAX_LINK_RATE 0x0001 +#define DPCD_ADDR_MAX_LANE_COUNT 0x0002 +#define DPCD_ADDR_LINK_BW_SET 0x0100 +#define DPCD_ADDR_LANE_COUNT_SET 0x0101 +#define DPCD_ADDR_TRAINING_PATTERN_SET 0x0102 +#define DPCD_ADDR_TRAINING_LANE0_SET 0x0103 +#define DPCD_ADDR_LANE0_1_STATUS 0x0202 +#define DPCD_ADDR_LANE_ALIGN__STATUS_UPDATED 0x0204 +#define DPCD_ADDR_ADJUST_REQUEST_LANE0_1 0x0206 +#define DPCD_ADDR_ADJUST_REQUEST_LANE2_3 0x0207 +#define DPCD_ADDR_TEST_REQUEST 0x0218 +#define DPCD_ADDR_TEST_RESPONSE 0x0260 +#define DPCD_ADDR_TEST_EDID_CHECKSUM 0x0261 +#define DPCD_ADDR_SINK_POWER_STATE 0x0600 + +/* DPCD_ADDR_MAX_LANE_COUNT */ +#define DPCD_MAX_LANE_COUNT_MASK 0x1f + +/* DPCD_ADDR_LANE_COUNT_SET */ +#define DPCD_ENHANCED_FRAME_EN (1 << 7) +#define DPCD_LANE_COUNT_SET_MASK 0x1f + +/* DPCD_ADDR_TRAINING_PATTERN_SET */ +#define DPCD_SCRAMBLING_DISABLED (1 << 5) +#define DPCD_SCRAMBLING_ENABLED (0 << 5) +#define DPCD_TRAINING_PATTERN_2 (2 << 0) +#define DPCD_TRAINING_PATTERN_1 (1 << 0) +#define DPCD_TRAINING_PATTERN_DISABLED (0 << 0) + +/* DPCD_ADDR_LANE0_1_STATUS */ +#define DPCD_LANE_SYMBOL_LOCKED (1 << 2) +#define DPCD_LANE_CHANNEL_EQ_DONE (1 << 1) +#define DPCD_LANE_CR_DONE (1 << 0) +#define DPCD_CHANNEL_EQ_BITS (DPCD_LANE_CR_DONE | \ + DPCD_LANE_CHANNEL_EQ_DONE | \ + DPCD_LANE_SYMBOL_LOCKED) + +/* DPCD_ADDR_LANE_ALIGN__STATUS_UPDATED */ +#define DPCD_LINK_STATUS_UPDATED (1 << 7) +#define DPCD_DOWNSTREAM_PORT_STATUS_CHANGED (1 << 6) +#define DPCD_INTERLANE_ALIGN_DONE (1 << 0) + +/* DPCD_ADDR_TEST_REQUEST */ +#define DPCD_TEST_EDID_READ (1 << 2) + +/* DPCD_ADDR_TEST_RESPONSE */ +#define DPCD_TEST_EDID_CHECKSUM_WRITE (1 << 2) + +/* DPCD_ADDR_SINK_POWER_STATE */ +#define DPCD_SET_POWER_STATE_D0 (1 << 0) +#define DPCD_SET_POWER_STATE_D4 (2 << 0) + +/* Allow DP Gating clock and set FIMD source to 267 Mhz for DP */ +void clock_init_dp_clock(void); + +/** + * Perform the next stage of the LCD init if it is time to do so. + * + * LCD init can be time-consuming because of the number of delays we need + * while waiting for the backlight power supply, etc. This function can + * be called at various times during U-Boot operation to advance the + * initialization of the LCD to the next stage if sufficient time has + * passed since the last stage. It keeps track of what stage it is up to + * and the time that it is permitted to move to the next stage. + * + * The final call should have can_block=1 to complete the init. + * + * @param blob fdt blob containing LCD information + * @param can_block 1 to wait until all init is complete, and then return + * 0 to return immediately, potentially doing nothing if it + * is not yet time for the next init. + */ +int exynos_lcd_check_next_stage(const void *blob, int can_block); +#endif diff --git a/src/include/cpu/samsung/exynos5250/sata.h b/src/include/cpu/samsung/exynos5250/sata.h new file mode 100644 index 0000000..912228e --- /dev/null +++ b/src/include/cpu/samsung/exynos5250/sata.h @@ -0,0 +1,27 @@ +/* + * Copyright (c) 2012 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 + */ +#ifndef __EXYNOS5_SATA_H +#define __EXYNOS5_SATA_H + +int exynos5_sata_init(const void *blob); +#endif + diff --git a/src/include/cpu/samsung/exynos5250/spi.h b/src/include/cpu/samsung/exynos5250/spi.h new file mode 100644 index 0000000..3430ac1 --- /dev/null +++ b/src/include/cpu/samsung/exynos5250/spi.h @@ -0,0 +1,89 @@ +/* + * (C) Copyright 2012 SAMSUNG Electronics + * Padmavathi Venna padma.v@samsung.com + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef __ASM_ARCH_EXYNOS_COMMON_SPI_H_ +#define __ASM_ARCH_EXYNOS_COMMON_SPI_H_ + +#ifndef __ASSEMBLY__ + +/* SPI peripheral register map; padded to 64KB */ +struct exynos_spi { + unsigned int ch_cfg; /* 0x00 */ + unsigned char reserved0[4]; + unsigned int mode_cfg; /* 0x08 */ + unsigned int cs_reg; /* 0x0c */ + unsigned char reserved1[4]; + unsigned int spi_sts; /* 0x14 */ + unsigned int tx_data; /* 0x18 */ + unsigned int rx_data; /* 0x1c */ + unsigned int pkt_cnt; /* 0x20 */ + unsigned char reserved2[4]; + unsigned int swap_cfg; /* 0x28 */ + unsigned int fb_clk; /* 0x2c */ + unsigned char padding[0xffd0]; +}; + +#define EXYNOS_SPI_MAX_FREQ 50000000 + +#define SPI_TIMEOUT_MS 10 + +#define SF_READ_DATA_CMD 0x3 + +/* SPI_CHCFG */ +#define SPI_CH_HS_EN (1 << 6) +#define SPI_CH_RST (1 << 5) +#define SPI_SLAVE_MODE (1 << 4) +#define SPI_CH_CPOL_L (1 << 3) +#define SPI_CH_CPHA_B (1 << 2) +#define SPI_RX_CH_ON (1 << 1) +#define SPI_TX_CH_ON (1 << 0) + +/* SPI_MODECFG */ +#define SPI_MODE_CH_WIDTH_WORD (0x2 << 29) +#define SPI_MODE_BUS_WIDTH_WORD (0x2 << 17) + +/* SPI_CSREG */ +#define SPI_SLAVE_SIG_INACT (1 << 0) + +/* SPI_STS */ +#define SPI_ST_TX_DONE (1 << 25) +#define SPI_FIFO_LVL_MASK 0x1ff +#define SPI_TX_LVL_OFFSET 6 +#define SPI_RX_LVL_OFFSET 15 + +/* Feedback Delay */ +#define SPI_CLK_BYPASS (0 << 0) +#define SPI_FB_DELAY_90 (1 << 0) +#define SPI_FB_DELAY_180 (2 << 0) +#define SPI_FB_DELAY_270 (3 << 0) + +/* Packet Count */ +#define SPI_PACKET_CNT_EN (1 << 16) + +/* Swap config */ +#define SPI_TX_SWAP_EN (1 << 0) +#define SPI_TX_BYTE_SWAP (1 << 2) +#define SPI_TX_HWORD_SWAP (1 << 3) +#define SPI_TX_BYTE_SWAP (1 << 2) +#define SPI_RX_SWAP_EN (1 << 4) +#define SPI_RX_BYTE_SWAP (1 << 6) +#define SPI_RX_HWORD_SWAP (1 << 7) + +#endif /* __ASSEMBLY__ */ +#endif diff --git a/src/include/cpu/samsung/exynos5250/sys_proto.h b/src/include/cpu/samsung/exynos5250/sys_proto.h new file mode 100644 index 0000000..f25dcd1 --- /dev/null +++ b/src/include/cpu/samsung/exynos5250/sys_proto.h @@ -0,0 +1,27 @@ +/* + * (C) Copyright 2012 Samsung Electronics + * Minkyu Kang mk7.kang@samsung.com + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + */ + +#ifndef __ASM_ARM_ARCH_EXYNOS5_SYS_PROTO_H__ +#define __ASM_ARM_ARCH_EXYNOS5_SYS_PROTO_H__ + +#include <asm/arch-exynos/sys_proto.h> + +#endif /* __ASM_ARM_ARCH_EXYNOS5_SYS_PROTO_H__ */ diff --git a/src/include/cpu/samsung/exynos5250/sysreg.h b/src/include/cpu/samsung/exynos5250/sysreg.h new file mode 100644 index 0000000..f081495 --- /dev/null +++ b/src/include/cpu/samsung/exynos5250/sysreg.h @@ -0,0 +1,36 @@ +/* + * (C) Copyright 2012 Samsung Electronics + * Register map for Exynos5 sysreg + * + * 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 __EXYNOS5_SYSREG_H__ +#define __EXYNOS5_SYSREG_H__ + +/* sysreg map */ +struct exynos5_sysreg { + /* Add registers as and when required */ + unsigned char res1[0x214]; + unsigned int disp1blk_cfg; + unsigned char res2[0x18]; + unsigned int usb20_phy_cfg; +}; + +#define FIMDBYPASS_DISP1 (1 << 15) +#define USB20_PHY_CFG_EN (1 << 0) + +#endif diff --git a/src/include/cpu/samsung/exynos5250/tzpc.h b/src/include/cpu/samsung/exynos5250/tzpc.h new file mode 100644 index 0000000..b9937b8 --- /dev/null +++ b/src/include/cpu/samsung/exynos5250/tzpc.h @@ -0,0 +1,52 @@ +/* + * (C) Copyright 2012 Samsung Electronics + * + * 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 __TZPC_H_ +#define __TZPC_H_ + +#ifndef __ASSEMBLER__ +struct exynos5_tzpc { + unsigned int r0size; + char res1[0x7FC]; + unsigned int decprot0stat; + unsigned int decprot0set; + unsigned int decprot0clr; + unsigned int decprot1stat; + unsigned int decprot1set; + unsigned int decprot1clr; + unsigned int decprot2stat; + unsigned int decprot2set; + unsigned int decprot2clr; + unsigned int decprot3stat; + unsigned int decprot3set; + unsigned int decprot3clr; + char res2[0x7B0]; + unsigned int periphid0; + unsigned int periphid1; + unsigned int periphid2; + unsigned int periphid3; + unsigned int pcellid0; + unsigned int pcellid1; + unsigned int pcellid2; + unsigned int pcellid3; +}; +#endif + +#endif diff --git a/src/include/cpu/samsung/exynos5250/uart.h b/src/include/cpu/samsung/exynos5250/uart.h new file mode 100644 index 0000000..8190c67 --- /dev/null +++ b/src/include/cpu/samsung/exynos5250/uart.h @@ -0,0 +1,71 @@ +/* + * (C) Copyright 2012 The ChromiumOS Authors + * (C) Copyright 2009 Samsung Electronics + * Minkyu Kang mk7.kang@samsung.com + * Heungjun Kim riverful.kim@samsung.com + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + * This file is based off of arch/arm/include/asm/arch-exynos5/uart.h + * from u-boot. + */ + +#ifndef __EXYNOS5_UART_H_ +#define __EXYNOS5_UART_H_ + +#include <types.h> + +/* FIXME: should these move into a Kconfig file? */ +#define EXYNOS5_UART0_BASE 0x12c00000 +#define EXYNOS5_UART1_BASE 0x12c10000 +#define EXYNOS5_UART2_BASE 0x12c20000 +#define EXYNOS5_UART3_BASE 0x12c30000 +#define EXYNOS5_ISP_UART_BASE 0x13190000 + +#if 0 +/* baudrate rest value */ +union br_rest { + unsigned short slot; /* udivslot */ + unsigned char value; /* ufracval */ +}; +#endif + +struct s5p_uart { + uint32_t ulcon; + uint32_t ucon; + uint32_t ufcon; + uint32_t umcon; + uint32_t utrstat; + uint32_t uerstat; + uint32_t ufstat; + uint32_t umstat; + uint8_t utxh; + uint8_t res1[3]; + uint8_t urxh; + uint8_t res2[3]; + uint32_t ubrdiv; + uint32_t ufracval; + uint32_t uintp; + uint32_t uints; + uint32_t uintm; +}; + +static inline int s5p_uart_divslot(void) +{ + return 0; +} + +#endif diff --git a/src/include/cpu/samsung/exynos5250/watchdog.h b/src/include/cpu/samsung/exynos5250/watchdog.h new file mode 100644 index 0000000..f35dde4 --- /dev/null +++ b/src/include/cpu/samsung/exynos5250/watchdog.h @@ -0,0 +1,27 @@ +/* + * (C) Copyright 2012 Samsung Electronics + * Minkyu Kang mk7.kang@samsung.com + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + */ + +#ifndef __ASM_ARM_ARCH_EXYNOS5_WATCHDOG_H__ +#define __ASM_ARM_ARCH_EXYNOS5_WATCHDOG_H__ + +#include <asm/arch-exynos/watchdog.h> + +#endif /* __ASM_ARM_ARCH_EXYNOS5_WATCHDOG_H__ */ diff --git a/src/include/device/i2c.h b/src/include/device/i2c.h new file mode 100644 index 0000000..f1275e3 --- /dev/null +++ b/src/include/device/i2c.h @@ -0,0 +1,279 @@ +/* + * (C) Copyright 2001 + * Gerald Van Baren, Custom IDEAS, vanbaren@cideas.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 + * + * The original I2C interface was + * (C) 2000 by Paolo Scaffardi (arsenio@tin.it) + * AIRVENT SAM s.p.a - RIMINI(ITALY) + * but has been changed substantially. + */ + +#ifndef _I2C_H_ +#define _I2C_H_ + +/* + * WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING + * + * The implementation MUST NOT use static or global variables if the + * I2C routines are used to read SDRAM configuration information + * because this is done before the memories are initialized. Limited + * use of stack-based variables are OK (the initial stack size is + * limited). + * + * WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING + */ + +/* + * Configuration items. + */ +#define I2C_RXTX_LEN 128 /* maximum tx/rx buffer length */ + +#ifdef CONFIG_I2C_MULTI_BUS +#define MAX_I2C_BUS 2 +#define I2C_MULTI_BUS 1 +#else +#define MAX_I2C_BUS 1 +#define I2C_MULTI_BUS 0 +#endif + +#if !defined(CONFIG_SYS_MAX_I2C_BUS) +#define CONFIG_SYS_MAX_I2C_BUS MAX_I2C_BUS +#endif + +/* define the I2C bus number for RTC and DTT if not already done */ +#if !defined(CONFIG_SYS_RTC_BUS_NUM) +#define CONFIG_SYS_RTC_BUS_NUM 0 +#endif +#if !defined(CONFIG_SYS_DTT_BUS_NUM) +#define CONFIG_SYS_DTT_BUS_NUM 0 +#endif +#if !defined(CONFIG_SYS_SPD_BUS_NUM) +#define CONFIG_SYS_SPD_BUS_NUM 0 +#endif + +#ifndef I2C_SOFT_DECLARATIONS +# if defined(CONFIG_MPC8260) +# define I2C_SOFT_DECLARATIONS volatile ioport_t *iop = ioport_addr((immap_t *)CONFIG_SYS_IMMR, I2C_PORT); +# elif defined(CONFIG_8xx) +# define I2C_SOFT_DECLARATIONS volatile immap_t *immr = (immap_t *)CONFIG_SYS_IMMR; + +# elif (defined(CONFIG_AT91RM9200) || \ + defined(CONFIG_AT91SAM9260) || defined(CONFIG_AT91SAM9261) || \ + defined(CONFIG_AT91SAM9263)) && !defined(CONFIG_AT91_LEGACY) +# define I2C_SOFT_DECLARATIONS at91_pio_t *pio = (at91_pio_t *) ATMEL_BASE_PIOA; +# else +# define I2C_SOFT_DECLARATIONS +# endif +#endif + +#ifdef CONFIG_8xx +/* Set default value for the I2C bus speed on 8xx. In the + * future, we'll define these in all 8xx board config files. + */ +#ifndef CONFIG_SYS_I2C_SPEED +#define CONFIG_SYS_I2C_SPEED 50000 +#endif +#endif + +/* + * Many boards/controllers/drivers don't support an I2C slave interface so + * provide a default slave address for them for use in common code. A real + * value for CONFIG_SYS_I2C_SLAVE should be defined for any board which does + * support a slave interface. + */ +#ifndef CONFIG_SYS_I2C_SLAVE +#define CONFIG_SYS_I2C_SLAVE 0xfe +#endif + +/* + * Initialization, must be called once on start up, may be called + * repeatedly to change the speed and slave addresses. + */ +void i2c_init(int speed, int slaveaddr); +void i2c_init_board(void); +#ifdef CONFIG_SYS_I2C_BOARD_LATE_INIT +void i2c_board_late_init(void); +#endif + +#if defined(CONFIG_I2C_MUX) + +typedef struct _mux { + uchar chip; + uchar channel; + char *name; + struct _mux *next; +} I2C_MUX; + +typedef struct _mux_device { + int busid; + I2C_MUX *mux; /* List of muxes, to reach the device */ + struct _mux_device *next; +} I2C_MUX_DEVICE; + +I2C_MUX_DEVICE *i2c_mux_search_device(int id); +I2C_MUX_DEVICE *i2c_mux_ident_muxstring (uchar *buf); +int i2x_mux_select_mux(int bus); +int i2c_mux_ident_muxstring_f (uchar *buf); +#endif + +/* + * Probe the given I2C chip address. Returns 0 if a chip responded, + * not 0 on failure. + */ +int i2c_probe(uchar chip); + +/* + * Read/Write interface: + * chip: I2C chip address, range 0..127 + * addr: Memory (register) address within the chip + * alen: Number of bytes to use for addr (typically 1, 2 for larger + * memories, 0 for register type devices with only one + * register) + * buffer: Where to read/write the data + * len: How many bytes to read/write + * + * Returns: 0 on success, not 0 on failure + */ +int i2c_read(uchar chip, uint addr, int alen, uchar *buffer, int len); +int i2c_write(uchar chip, uint addr, int alen, uchar *buffer, int len); + +/* + * Utility routines to read/write registers. + */ +static inline u8 i2c_reg_read(u8 addr, u8 reg) +{ + u8 buf; + +#ifdef CONFIG_8xx + /* MPC8xx needs this. Maybe one day we can get rid of it. */ + i2c_init(CONFIG_SYS_I2C_SPEED, CONFIG_SYS_I2C_SLAVE); +#endif + +#ifdef DEBUG + printf("%s: addr=0x%02x, reg=0x%02x\n", __func__, addr, reg); +#endif + + i2c_read(addr, reg, 1, &buf, 1); + + return buf; +} + +static inline void i2c_reg_write(u8 addr, u8 reg, u8 val) +{ +#ifdef CONFIG_8xx + /* MPC8xx needs this. Maybe one day we can get rid of it. */ + i2c_init(CONFIG_SYS_I2C_SPEED, CONFIG_SYS_I2C_SLAVE); +#endif + +#ifdef DEBUG + printf("%s: addr=0x%02x, reg=0x%02x, val=0x%02x\n", + __func__, addr, reg, val); +#endif + + i2c_write(addr, reg, 1, &val, 1); +} + +/* + * Functions for setting the current I2C bus and its speed + */ + +/* + * i2c_set_bus_num: + * + * Change the active I2C bus. Subsequent read/write calls will + * go to this one. + * + * bus - bus index, zero based + * + * Returns: 0 on success, not 0 on failure + * + */ +int i2c_set_bus_num(unsigned int bus); + +/* + * i2c_get_bus_num: + * + * Returns index of currently active I2C bus. Zero-based. + */ + +unsigned int i2c_get_bus_num(void); + +/* + * i2c_set_bus_speed: + * + * Change the speed of the active I2C bus + * + * speed - bus speed in Hz + * + * Returns: 0 on success, not 0 on failure + * + */ +int i2c_set_bus_speed(unsigned int); + +/* + * i2c_get_bus_speed: + * + * Returns speed of currently active I2C bus in Hz + */ + +unsigned int i2c_get_bus_speed(void); + +/* NOTE: These two functions MUST be always_inline to avoid code growth! */ +static inline unsigned int I2C_GET_BUS(void) __attribute__((always_inline)); +static inline unsigned int I2C_GET_BUS(void) +{ + return I2C_MULTI_BUS ? i2c_get_bus_num() : 0; +} + +static inline void I2C_SET_BUS(unsigned int bus) __attribute__((always_inline)); +static inline void I2C_SET_BUS(unsigned int bus) +{ + if (I2C_MULTI_BUS) + i2c_set_bus_num(bus); +} + +/* + * Set an early register base for a given i2c peripheral. + * This is used to access a single i2c bus early on in the boot sequence. + * + * @param base: The base address of the i2c peripheral's register map + */ +void i2c_set_early_reg(unsigned int base); + +/** + * Find the I2C bus number by given a FDT I2C node. + * + * @param blob Device tree blbo + * @param node FDT I2C node to find + * @return the number of I2C bus (zero based), or -1 on error + */ +int i2c_get_bus_num_fdt(const void *blob, int node); + +/** + * Reset the I2C bus represented by the given a FDT I2C node. + * + * @param blob Device tree blbo + * @param node FDT I2C node to find + * @return 0 if port was reset, -1 if not found + */ +int i2c_reset_port_fdt(const void *blob, int node); + +#endif /* _I2C_H_ */ diff --git a/src/include/device/power/max77686.h b/src/include/device/power/max77686.h new file mode 100644 index 0000000..345471e --- /dev/null +++ b/src/include/device/power/max77686.h @@ -0,0 +1,134 @@ +/* + * Copyright (C) 2012 Samsung Electronics + * Alim Akhtar alim.akhtar@samsung.com + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +#ifndef __MAX77686_H_ +#define __MAX77686_H_ + +enum max77686_regnum { + PMIC_BUCK1 = 0, + PMIC_BUCK2, + PMIC_BUCK3, + PMIC_BUCK4, + PMIC_BUCK5, + PMIC_BUCK6, + PMIC_BUCK7, + PMIC_BUCK8, + PMIC_BUCK9, + PMIC_LDO1, + PMIC_LDO2, + PMIC_LDO3, + PMIC_LDO4, + PMIC_LDO5, + PMIC_LDO6, + PMIC_LDO7, + PMIC_LDO8, + PMIC_LDO9, + PMIC_LDO10, + PMIC_LDO11, + PMIC_LDO12, + PMIC_LDO13, + PMIC_LDO14, + PMIC_LDO15, + PMIC_LDO16, + PMIC_LDO17, + PMIC_LDO18, + PMIC_LDO19, + PMIC_LDO20, + PMIC_LDO21, + PMIC_LDO22, + PMIC_LDO23, + PMIC_LDO24, + PMIC_LDO25, + PMIC_LDO26, + PMIC_EN32KHZ_CP, +}; + +/** + * struct max77686_para - max77686 register parameters + * @param vol_addr i2c address of the given buck/ldo register + * @param vol_bitpos bit position to be set or clear within register + * @param vol_bitmask bit mask value + * @param reg_enaddr control register address, which enable the given + * given buck/ldo. + * @param reg_enbitpos bit position to be enabled + * @param reg_enbiton value to be written to buck/ldo to make it ON + * @param reg_enbitoff value to be written to buck/ldo to make it OFF + * @param vol_min minimum voltage level supported by given buck/ldo + * @param vol_div voltage division value of given buck/ldo + */ +struct max77686_para { + enum max77686_regnum regnum; + u8 vol_addr; + u8 vol_bitpos; + u8 vol_bitmask; + u8 reg_enaddr; + u8 reg_enbitpos; + u8 reg_enbitmask; + u8 reg_enbiton; + u8 reg_enbitoff; + u32 vol_min; + u32 vol_div; +}; + +/* I2C device address for pmic max77686 */ +#define MAX77686_I2C_ADDR (0x12 >> 1) + +enum { + REG_DISABLE = 0, + REG_ENABLE +}; + +enum { + MAX77686_MV = 0, /* mili volt */ + MAX77686_UV /* micro volt */ +}; + +/** + * This function enables the 32KHz coprocessor clock. + * + * Return 0 if ok, else -1 + */ +int max77686_enable_32khz_cp(void); + +/** + * Set the required voltage level of pmic + * + * @param reg register number of buck/ldo to be set + * @param volt voltage level to be set + * @param enable enable or disable bit + * @param volt_units MAX77686_MV or MAX77686_UV, unit of the + * voltage parameters + * + * @return Return 0 if ok, else -1 + */ +int max77686_volsetting(enum max77686_regnum reg, unsigned int volt, + int enable, int volt_units); + +/** + * Disable charging of the RTC backup battery + * + * @return Return 0 if ok, else -1 + */ +int max77686_disable_backup_batt(void); + +#endif /* __MAX77686_PMIC_H_ */ diff --git a/src/include/stddef.h b/src/include/stddef.h new file mode 100644 index 0000000..888d497 --- /dev/null +++ b/src/include/stddef.h @@ -0,0 +1,24 @@ +#ifndef STDDEF_H +#define STDDEF_H + +typedef long ptrdiff_t; +#ifndef __SIZE_TYPE__ +#define __SIZE_TYPE__ unsigned long +#endif +typedef __SIZE_TYPE__ size_t; +typedef long ssize_t; + +typedef int wchar_t; +typedef unsigned int wint_t; + +#define NULL ((void *)0) + +#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER) + +#ifdef __PRE_RAM__ +#define ROMSTAGE_CONST const +#else +#define ROMSTAGE_CONST +#endif + +#endif /* STDDEF_H */ diff --git a/src/include/uart.h b/src/include/uart.h new file mode 100644 index 0000000..931d6dc --- /dev/null +++ b/src/include/uart.h @@ -0,0 +1,33 @@ +/* + * 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 + * + * FIXME(dhendrix): This file contains generic prototypes for UART functions. + * The existing headers are too specific to the 8250, so we need a better + * abstraction for use with non-8250 UARTs. + */ + +#ifndef UART_H +#define UART_H + +unsigned char uart_rx_byte(void); +void uart_tx_byte(unsigned char data); +void uart_tx_flush(void); + +void uart_init(void); + +#endif /* UART_H */ diff --git a/src/lib/Makefile.inc b/src/lib/Makefile.inc index 3b16170..6b3f0d8 100644 --- a/src/lib/Makefile.inc +++ b/src/lib/Makefile.inc @@ -60,7 +60,7 @@ ramstage-y += cbfs.c ramstage-y += lzma.c #ramstage-y += lzmadecode.c ramstage-y += stack.c -ramstage-y += gcc.c +ramstage-$(CONFIG_ARCH_X86) += gcc.c ramstage-y += clog2.c ramstage-y += cbmem.c ramstage-$(CONFIG_CONSOLE_SERIAL8250) += uart8250.c diff --git a/src/mainboard/Kconfig b/src/mainboard/Kconfig index da76327..734aaf2 100644 --- a/src/mainboard/Kconfig +++ b/src/mainboard/Kconfig @@ -58,6 +58,8 @@ config VENDOR_GETAC bool "Getac" config VENDOR_GIGABYTE bool "GIGABYTE" +config VENDOR_GOOGLE + bool "Google" config VENDOR_HP bool "HP" config VENDOR_IBASE @@ -158,6 +160,7 @@ source "src/mainboard/ecs/Kconfig" source "src/mainboard/emulation/Kconfig" source "src/mainboard/getac/Kconfig" source "src/mainboard/gigabyte/Kconfig" +source "src/mainboard/google/Kconfig" source "src/mainboard/hp/Kconfig" source "src/mainboard/ibase/Kconfig" source "src/mainboard/ibm/Kconfig" @@ -304,6 +307,19 @@ config ROM_SIZE default 0x800000 if COREBOOT_ROMSIZE_KB_8192 default 0x1000000 if COREBOOT_ROMSIZE_KB_16384
+# FIXME: does this need to be here or in sandybridge/ ? +#config CBFS_SIZE +# hex +# default ROM_SIZE + +config CACHE_ROM_SIZE + hex + default ROM_SIZE + +config CACHE_ROM_SIZE + hex + default CBFS_SIZE + config ENABLE_POWER_BUTTON bool "Enable the power button" if POWER_BUTTON_IS_OPTIONAL default y if POWER_BUTTON_DEFAULT_ENABLE diff --git a/src/mainboard/google/Kconfig b/src/mainboard/google/Kconfig new file mode 100644 index 0000000..126a37d --- /dev/null +++ b/src/mainboard/google/Kconfig @@ -0,0 +1,17 @@ +if VENDOR_GOOGLE + +choice + prompt "Mainboard model" + +config BOARD_GOOGLE_SNOW + bool "Snow" + +endchoice + +source "src/mainboard/google/snow/Kconfig" + +config MAINBOARD_VENDOR + string + default "Google" + +endif # VENDOR_GOOGLE diff --git a/src/mainboard/google/snow/Kconfig b/src/mainboard/google/snow/Kconfig new file mode 100644 index 0000000..eedccba --- /dev/null +++ b/src/mainboard/google/snow/Kconfig @@ -0,0 +1,162 @@ +if BOARD_GOOGLE_SNOW + +config BOARD_SPECIFIC_OPTIONS # dummy + def_bool y + select ARCH_ARMV7 + select CPU_SAMSUNG_EXYNOS5 + select HAVE_UART_MEMORY_MAPPED + select CONSOLE_SERIAL_NONSTANDARD_MEM # enable serial debugging +# select NORTHBRIDGE_INTEL_IVYBRIDGE +# select EC_GOOGLE_CHROMEEC + select BOARD_ROMSIZE_KB_4096 + select DRIVER_MAXIM_77686 +# select HAVE_ACPI_TABLES +# select MMCONF_SUPPORT +# select CHROMEOS + +config MAINBOARD_DIR + string + default google/snow + +config MAINBOARD_PART_NUMBER + string + default "SNOW" + +#config MMCONF_BASE_ADDRESS +# hex +# default 0xf0000000 + +#config IRQ_SLOT_COUNT +# int +# default 18 + +config MAX_CPUS + int + default 2 + +config MAINBOARD_VENDOR + string + default "Samsung" + +# SPL (second-phase loader) stuff +config SPL_TEXT_BASE + hex "SPL executable base" + default 0x02023400 + help + Location of SPL. Default location is within iRAM region. + +#FIXME: increased "SPL" size to get around build issues +#config SPL_MAX_SIZE +# hex "SPL executable max size" +# default 0x3800 +# help +# Max size of SPL. Default is 14KB +config SPL_MAX_SIZE + hex "SPL executable max size" + default 0x8000 + help + Max size of SPL. Let's say 32KB for now... + +config DRAM_SIZE_MB + int "DRAM size (MB)" + default 2048 + +config NR_DRAM_BANKS + int "Number of DRAM banks" + default 1 + +choice + prompt "Serial Console UART" + default CONSOLE_SERIAL_UART3 + depends on CONSOLE_SERIAL_NONSTANDARD_MEM + +config CONSOLE_SERIAL_UART0 + bool "UART0" + help + Serial console on UART0 + +config CONSOLE_SERIAL_UART1 + bool "UART1" + help + Serial console on UART1 + +config CONSOLE_SERIAL_UART2 + bool "UART2" + help + Serial console on UART2 + +config CONSOLE_SERIAL_UART3 + bool "UART3" + help + Serial console on UART3 + +endchoice + +config CONSOLE_SERIAL_UART_ADDRESS + hex + depends on CONSOLE_SERIAL_NONSTANDARD_MEM + default 0x12c00000 if CONSOLE_SERIAL_UART0 + default 0x12c10000 if CONSOLE_SERIAL_UART1 + default 0x12c20000 if CONSOLE_SERIAL_UART2 + default 0x12c30000 if CONSOLE_SERIAL_UART3 + help + Map the UART names to the respective MMIO address. + +################################################################# +# stuff from smdk5250.h # +# FIXME: can we move some of these to exynos5250's Kconfig? # +################################################################# +config SYS_I2C_SPEED + int + default 100000 + +config SYS_I2C_SLAVE + hex + default 0x0 + +config I2C_MULTI_BUS + bool + default y + +#config HARD_I2C +# bool +# default y +#CMD_I2C +#I2C_EDID +#DRIVER_S3C24X0_I2C + +config VDD_ARM_MV + int + default 1300 #1.3V + +config VDD_INT_UV + int + default 1012500 # 1.0125v + +config VDD_MIF_MV + int + default 1000 # 1.0v + +config VDD_G3D_MV + int + default 1200 # 1.2v + +config VDD_LDO2_MV + int + default 1500 # 1.5v + +config VDD_LDO3_MV + int + default 1800 # 1.8v + +config VDD_LDO5_MV + int + default 1800 # 1.8v + +config VDD_LDO10_MV + int + default 1800 # 1.8v + +######### smdk5250.h ######## + +endif # BOARD_GOOGLE_SNOW diff --git a/src/mainboard/google/snow/Makefile.inc b/src/mainboard/google/snow/Makefile.inc new file mode 100644 index 0000000..01488d0 --- /dev/null +++ b/src/mainboard/google/snow/Makefile.inc @@ -0,0 +1,36 @@ +## +## 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 +## + +#romstage-y += romstage.c + +# ramstage-y += ec.c + +# FIXME: smdk5250_spl and mainboard.c are a mess. In the long +# run we'll want to replace low-level code that calls mainboard code +# with mainboard code that calls low-level code with appropriate +# parameters. Grep around for spl_get_machine_params for examples. +romstage-y += smdk5250_spl.c +ramstage-y += smdk5250_spl.c +#ramstage-y += mainboard.c + +# romstage-$(CONFIG_CHROMEOS) += chromeos.c + +# FIXME: we should do something similar to x86 platforms for Snow SPDs + +SRC_ROOT = $(src)/mainboard/google/snow diff --git a/src/mainboard/google/snow/board.h b/src/mainboard/google/snow/board.h new file mode 100644 index 0000000..bedd740 --- /dev/null +++ b/src/mainboard/google/snow/board.h @@ -0,0 +1,33 @@ +/* + * Board header file for Exynos boards + * + * 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 + */ + +#ifndef __SAMSUNG_BOARD_H +#define __SAMSUNG_BOARD_H + +/* Init the SPI driver */ +void spi_init(void); + +/* Init the I2C driver */ +void board_i2c_init(const void *blob); + +#endif diff --git a/src/mainboard/google/snow/devicetree.cb b/src/mainboard/google/snow/devicetree.cb new file mode 100644 index 0000000..1d9d553 --- /dev/null +++ b/src/mainboard/google/snow/devicetree.cb @@ -0,0 +1,7 @@ +# FIXME: this is just a stub for now +chip cpu/samsung/exynos5250 + chip drivers/generic/generic # I2C0 controller + device i2c 6 on end # ? + device i2c 9 on end # ? + end +end diff --git a/src/mainboard/google/snow/mainboard.c b/src/mainboard/google/snow/mainboard.c new file mode 100644 index 0000000..8afac3c --- /dev/null +++ b/src/mainboard/google/snow/mainboard.c @@ -0,0 +1,943 @@ +/* + * Copyright (C) 2012 Samsung Electronics + * + * 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: Note: Most of this is taken from U-Boot. Coreboot stuff is + * appended at the end. Also, much of this should be broken up into + * smaller files anyway. + */ + +#include <device/device.h> +#if 0 /* big #if */ +#include <common.h> +#include <fdtdec.h> +#include <i2c.h> +#include <max77686.h> +#include <mkbp.h> +#include <mmc.h> +#include <netdev.h> +#include <tps65090.h> +#include <errno.h> +#include <asm/gpio.h> +#include <asm/arch/clock.h> +#include <cpu/samsung/exynos5250/cpu.h> +#include <asm/arch/ehci-s5p.h> +#include <asm/arch/board.h> +#include <asm/arch/gpio.h> +#include <asm/arch/mmc.h> +#include <asm/arch/mshc.h> +#include <asm/arch/pinmux.h> +#include <asm/arch/sromc.h> +#include <asm/arch-exynos5/power.h> +#include <asm/arch/sata.h> +#include <asm/arch/exynos-tmu.h> +#include <asm/arch/exynos-cpufreq.h> +#include <asm/arch/s5p-dp.h> + +#include "board.h" + +#ifndef CONFIG_EXYNOS_DISPLAYPORT +#error "CONFIG_EXYNOS_DISPLAYPORT must be defined for smdk5250" +#endif + +DECLARE_GLOBAL_DATA_PTR; + +struct local_info { + struct mkbp_dev *mkbp_dev; /* Pointer to mkbp device */ + int arbitrate_node; + struct fdt_gpio_state ap_claim; + struct fdt_gpio_state ec_claim; + + /* DisplayPort gpios */ + struct fdt_gpio_state dp_pd; + struct fdt_gpio_state dp_rst; + struct fdt_gpio_state dp_hpd; + + /* Time between requesting bus and deciding that we have it */ + unsigned slew_delay_us; + + /* Time between retrying to see if the AP has released the bus */ + unsigned wait_retry_ms; + + /* Time to wait until the bus becomes free */ + unsigned wait_free_ms; +}; + +static struct local_info local; +static uint32_t cpufreq_loop_count; + +/* + * Called to do the needful when tstc has a character ready + * Meant to work in contrast to board_poll_devices + */ +void board_tstc_ready(void) +{ +#ifdef CONFIG_EXYNOS_CPUFREQ + if (cpufreq_loop_count >= 10000000) { + /* Character received, increase ARM frequency */ + exynos5250_set_frequency(CPU_FREQ_L1700); + } + cpufreq_loop_count = 0; +#endif /* CONFIG_EXYNOS_CPUFREQ */ +} + +/* + * Polling various devices on board for details and status monitoring purposes + */ +void board_poll_devices(void) +{ +#if defined CONFIG_EXYNOS_TMU + int temp; + + switch (tmu_monitor(&temp)) { + case TMU_STATUS_TRIPPED: + puts("EXYNOS_TMU: TRIPPING! Device power going down ...\n"); + power_shutdown(); + break; + case TMU_STATUS_WARNING: + puts("EXYNOS_TMU: WARNING! Temperature very high\n"); + break; + case TMU_STATUS_INIT: + case TMU_STATUS_NORMAL: + break; + default: + debug("Unknown TMU state\n"); + } +#endif /* CONFIG_EXYNOS_TMU */ +#ifdef CONFIG_EXYNOS_CPUFREQ + cpufreq_loop_count++; + if (cpufreq_loop_count == 10000000) { + /* User is idle, decrease ARM frequency*/ + exynos5250_set_frequency(CPU_FREQ_L200); + } +#endif /* CONFIG_EXYNOS_CPUFREQ */ +} + +#ifdef CONFIG_OF_CONTROL +static int decode_sromc(const void *blob, struct fdt_sromc *config) +{ + int err; + int node; + + node = fdtdec_next_compatible(blob, 0, COMPAT_SAMSUNG_EXYNOS5_SROMC); + if (node < 0) { + debug("Could not find SROMC node\n"); + return node; + } + + config->bank = fdtdec_get_int(blob, node, "bank", 0); + config->width = fdtdec_get_int(blob, node, "width", 2); + + err = fdtdec_get_int_array(blob, node, "srom-timing", config->timing, + FDT_SROM_TIMING_COUNT); + if (err < 0) { + debug("Could not decode SROMC configuration\n"); + return -FDT_ERR_NOTFOUND; + } + + return 0; +} +#endif + +#if 0 +/** + * Read and clear the marker value; then return the read value. + * + * This marker is set to EXYNOS5_SPL_MARKER when SPL runs. Then in U-Boot + * we can check (and clear) this marker to see if we were run from SPL. + * If we were called from another U-Boot, the marker will be clear. + * + * @return marker value (EXYNOS5_SPL_MARKER if we were run from SPL, else 0) + */ +static uint32_t exynos5_read_and_clear_spl_marker(void) +{ + uint32_t value, *marker = (uint32_t *)CONFIG_SPL_MARKER; + + value = *marker; + *marker = 0; + + return value; +} +#endif + +int board_is_processor_reset(void) +{ + static uint8_t inited, is_reset; + uint32_t marker_value; + + if (!inited) { + marker_value = exynos5_read_and_clear_spl_marker(); + is_reset = marker_value == EXYNOS5_SPL_MARKER; + inited = 1; + } + + return is_reset; +} + +int board_eth_init(bd_t *bis) +{ +#ifdef CONFIG_SMC911X + u32 smc_bw_conf, smc_bc_conf; + struct fdt_sromc config; + fdt_addr_t base_addr; + int node; + +#ifdef CONFIG_OF_CONTROL + node = decode_sromc(gd->fdt_blob, &config); + if (node < 0) { + debug("%s: Could not find sromc configuration\n", __func__); + return 0; + } + node = fdtdec_next_compatible(gd->fdt_blob, node, COMPAT_SMSC_LAN9215); + if (node < 0) { + debug("%s: Could not find lan9215 configuration\n", __func__); + return 0; + } + + /* We now have a node, so any problems from now on are errors */ + base_addr = fdtdec_get_addr(gd->fdt_blob, node, "reg"); + if (base_addr == FDT_ADDR_T_NONE) { + debug("%s: Could not find lan9215 address\n", __func__); + return -1; + } +#else + /* Non-FDT configuration - bank number and timing parameters*/ + config.bank = CONFIG_ENV_SROM_BANK; + config.width = 2; + + config.timing[FDT_SROM_TACS] = 0x01; + config.timing[FDT_SROM_TCOS] = 0x01; + config.timing[FDT_SROM_TACC] = 0x06; + config.timing[FDT_SROM_TCOH] = 0x01; + config.timing[FDT_SROM_TAH] = 0x0C; + config.timing[FDT_SROM_TACP] = 0x09; + config.timing[FDT_SROM_PMC] = 0x01; + base_addr = CONFIG_SMC911X_BASE; +#endif + + /* Ethernet needs data bus width of 16 bits */ + if (config.width != 2) { + debug("%s: Unsupported bus width %d\n", __func__, + config.width); + return -1; + } + smc_bw_conf = SROMC_DATA16_WIDTH(config.bank) + | SROMC_BYTE_ENABLE(config.bank); + + smc_bc_conf = SROMC_BC_TACS(config.timing[FDT_SROM_TACS]) |\ + SROMC_BC_TCOS(config.timing[FDT_SROM_TCOS]) |\ + SROMC_BC_TACC(config.timing[FDT_SROM_TACC]) |\ + SROMC_BC_TCOH(config.timing[FDT_SROM_TCOH]) |\ + SROMC_BC_TAH(config.timing[FDT_SROM_TAH]) |\ + SROMC_BC_TACP(config.timing[FDT_SROM_TACP]) |\ + SROMC_BC_PMC(config.timing[FDT_SROM_PMC]); + + /* Select and configure the SROMC bank */ + exynos_pinmux_config(PERIPH_ID_SROMC, config.bank | PINMUX_FLAG_16BIT); + s5p_config_sromc(config.bank, smc_bw_conf, smc_bc_conf); + return smc911x_initialize(0, base_addr); +#endif + return 0; +} + +int fdtdec_decode_memory(const void *blob, struct fdt_memory *config) +{ + int node, len; + const fdt_addr_t *cell; + + node = fdt_path_offset(blob, "/memory"); + if (node < 0) { + debug("Could not find the path /memory\n"); + return node; + } + cell = fdt_getprop(blob, node, "reg", &len); + if (cell && len == sizeof(fdt_addr_t) * 2) { + config->start = fdt_addr_to_cpu(cell[0]); + config->end = fdt_addr_to_cpu(cell[1]); + } else { + return -FDT_ERR_BADLAYOUT; + } + + return 0; +} + +int board_usb_vbus_init(void) +{ + /* Enable VBUS power switch */ + gpio_direction_output(GPIO_X11, 1); + /* VBUS turn ON time */ + mdelay(3); + + return 0; +} + +struct mkbp_dev *board_get_mkbp_dev(void) +{ + return local.mkbp_dev; +} + +/* + * This functions disable the USB3.0 PLL to save power + */ +static void disable_usb30_pll(void) +{ + int node, ret; + struct fdt_gpio_state en_gpio; + + node = fdtdec_next_compatible(gd->fdt_blob, 0, + COMPAT_SAMSUNG_EXYNOS_USB); + if (node < 0) + return; + + ret = fdtdec_decode_gpio(gd->fdt_blob, node, "usb3-pll-gpio", &en_gpio); + if (ret) + return; + + fdtdec_setup_gpio(&en_gpio); + gpio_direction_output(en_gpio.gpio, en_gpio.flags); +} + +static int board_init_mkbp_devices(const void *blob) +{ + local.mkbp_dev = mkbp_init(blob); + if (!local.mkbp_dev) { + debug("%s: cannot init mkbp device\n", __func__); + return -1; + } + + return 0; +} + +static int board_i2c_arb_init(const void *blob) +{ + int node; + + local.arbitrate_node = -1; + node = fdtdec_next_compatible(blob, 0, COMPAT_GOOGLE_ARBITRATOR); + if (node < 0) { + debug("Cannot find bus arbitrator node\n"); + return 0; + } + + if (fdtdec_decode_gpio(blob, node, "google,ap-claim-gpios", + &local.ap_claim) || + fdtdec_decode_gpio(blob, node, "google,ec-claim-gpios", + &local.ec_claim)) { + debug("Cannot find bus arbitrator GPIOs\n"); + return 0; + } + + if (fdtdec_setup_gpio(&local.ap_claim) || + fdtdec_setup_gpio(&local.ec_claim)) { + debug("Cannot claim arbitration GPIOs\n"); + return -1; + } + + /* We are currently not claiming the bus */ + gpio_direction_output(local.ap_claim.gpio, 1); + gpio_direction_input(local.ec_claim.gpio); + gpio_set_pull(local.ec_claim.gpio, EXYNOS_GPIO_PULL_UP); + + local.arbitrate_node = fdtdec_lookup_phandle(blob, node, + "google,arbitrate-bus"); + if (local.arbitrate_node < 0) { + debug("Cannot find bus to arbitrate\n"); + return -1; + } + + local.slew_delay_us = fdtdec_get_int(blob, node, + "google,slew-delay-us", 10); + local.wait_retry_ms = fdtdec_get_int(blob, node, + "google,wait-retry-us", 2000); + local.wait_retry_ms = DIV_ROUND_UP(local.wait_retry_ms, 1000); + local.wait_free_ms = fdtdec_get_int(blob, node, + "google,wait-free-us", 50000); + local.wait_free_ms = DIV_ROUND_UP(local.wait_free_ms, 1000); + debug("Bus arbitration ready on fdt node %d\n", local.arbitrate_node); + + return 0; +} + +/** + * Fix-up the kernel device tree so the bridge pd_n and rst_n gpios accurately + * reflect the current board rev. + */ +static void ft_board_setup_gpios(void *blob, bd_t *bd) +{ + int ret, rev, np, len; + const struct fdt_property *prop; + + /* Do nothing for newer boards */ + rev = board_get_revision(); + if (rev < 4 || rev == 6) + return; + + /* + * If this is an older board, replace powerdown-gpio contents with that + * of reset-gpio and delete reset-gpio from the dt. + */ + np = fdtdec_next_compatible(blob, 0, COMPAT_NXP_PTN3460); + if (np < 0) { + debug("%s: Could not find COMPAT_NXP_PTN3460\n", __func__); + return; + } + + prop = fdt_get_property(blob, np, "reset-gpio", &len); + if (!prop) { + debug("%s: Could not get property err=%d\n", __func__, len); + return; + } + + ret = fdt_setprop_inplace(blob, np, "powerdown-gpio", prop->data, + len); + if (ret) { + debug("%s: Could not setprop inplace err=%d\n", __func__, ret); + return; + } + + ret = fdt_delprop(blob, np, "reset-gpio"); + if (ret) { + debug("%s: Could not delprop err=%d\n", __func__, ret); + return; + } +} + +/** + * Fix-up the kernel device tree so the powered-while-resumed is added to MP + * device tree. + */ +static void ft_board_setup_tpm_resume(void *blob, bd_t *bd) +{ + const char kernel_tpm_compat[] = "infineon,slb9635tt"; + const char prop_name[] = "powered-while-suspended"; + int err, node, rev; + + /* Only apply fixup to MP machine */ + rev = board_get_revision(); + if (!(rev == 0 || rev == 3)) + return; + + node = fdt_node_offset_by_compatible(blob, 0, kernel_tpm_compat); + if (node < 0) { + debug("%s: fail to find %s: %d\n", __func__, + kernel_tpm_compat, node); + return; + } + + err = fdt_setprop(blob, node, prop_name, NULL, 0); + if (err) { + debug("%s: fail to setprop: %d\n", __func__, err); + return; + } +} + +void ft_board_setup(void *blob, bd_t *bd) +{ + ft_board_setup_gpios(blob, bd); + ft_board_setup_tpm_resume(blob, bd); +} + +#ifdef CONFIG_TPS65090_POWER +int board_dp_lcd_vdd(const void *blob, unsigned *wait_ms) +{ + *wait_ms = 0; + return tps65090_fet_enable(6); /* Enable FET6, lcd panel */ +} +#endif + +static int board_dp_fill_gpios(const void *blob) +{ + int np, ret, rev; + + np = fdtdec_next_compatible(blob, 0, COMPAT_NXP_PTN3460); + if (np < 0) { + debug("%s: Could not find COMPAT_NXP_PTN3460 (%d)\n", __func__, + ret); + return np; + } + ret = fdtdec_decode_gpio(blob, np, "powerdown-gpio", &local.dp_pd); + if (ret) { + debug("%s: Could not decode powerdown-gpio (%d)\n", __func__, + ret); + return ret; + } + ret = fdtdec_decode_gpio(blob, np, "reset-gpio", &local.dp_rst); + if (ret) { + debug("%s: Could not decode reset-gpio (%d)\n", __func__, ret); + return ret; + } + ret = fdtdec_decode_gpio(blob, np, "hotplug-gpio", &local.dp_hpd); + if (ret) { + debug("%s: Could not decode hotplug (%d)\n", __func__, ret); + return ret; + } + + /* If board is older, replace pd gpio with rst gpio */ + rev = board_get_revision(); + if (rev >= 4 && rev != 6) { + local.dp_pd = local.dp_rst; + local.dp_rst.gpio = FDT_GPIO_NONE; + } + return 0; +} + +int board_dp_bridge_setup(const void *blob, unsigned *wait_ms) +{ + int ret; + + ret = board_dp_fill_gpios(blob); + if (ret) + return ret; + + /* Mux HPHPD to the special hotplug detect mode */ + exynos_pinmux_config(PERIPH_ID_DPHPD, 0); + + /* Setup the GPIOs */ + ret = fdtdec_setup_gpio(&local.dp_pd); + if (ret) { + debug("%s: Could not setup pd gpio (%d)\n", __func__, ret); + return ret; + } + ret = fdtdec_setup_gpio(&local.dp_rst); + if (ret) { + debug("%s: Could not setup rst gpio (%d)\n", __func__, ret); + return ret; + } + ret = fdtdec_setup_gpio(&local.dp_hpd); + if (ret) { + debug("%s: Could not setup hpd gpio (%d)\n", __func__, ret); + return ret; + } + + fdtdec_set_gpio(&local.dp_pd, 0); + gpio_cfg_pin(local.dp_pd.gpio, EXYNOS_GPIO_OUTPUT); + gpio_set_pull(local.dp_pd.gpio, EXYNOS_GPIO_PULL_NONE); + if (fdt_gpio_isvalid(&local.dp_rst)) { + fdtdec_set_gpio(&local.dp_rst, 1); + gpio_cfg_pin(local.dp_rst.gpio, EXYNOS_GPIO_OUTPUT); + gpio_set_pull(local.dp_rst.gpio, EXYNOS_GPIO_PULL_NONE); + udelay(10); + fdtdec_set_gpio(&local.dp_rst, 0); + } + + *wait_ms = 0; + return 0; +} + +int board_dp_bridge_init(const void *blob, unsigned *wait_ms) +{ + /* De-assert PD (and possibly RST) to power up the bridge */ + fdtdec_set_gpio(&local.dp_pd, 0); + + /* Ignore the return value here, on some boards this is NC */ + fdtdec_set_gpio(&local.dp_rst, 0); + + /* + * We need to wait for 90ms after bringing up the bridge since there + * is a phantom "high" on the HPD chip during its bootup. The phantom + * high comes within 7ms of de-asserting PD and persists for at least + * 15ms. The real high comes roughly 50ms after PD is de-asserted. The + * phantom high makes it hard for us to know when the NXP chip is up. + */ + *wait_ms = 90; + return 0; +} + +int board_dp_bridge_reset(const void *blob, unsigned *wait_ms) +{ + debug("%s: eDP bridge failed to come up\n", __func__); + + /* + * If we're here, the bridge chip failed to initialize. + * Drive DP_N low in an attempt to reset. + */ + fdtdec_set_gpio(&local.dp_pd, 1); + + /* Ignore the return value here, on some boards this is NC */ + fdtdec_set_gpio(&local.dp_rst, 1); + + /* + * Arbitrarily wait 300ms here with DP_N low. Don't know for + * sure how long we should wait, but we're being paranoid. + */ + *wait_ms = 300; + return 0; +} + +int board_dp_hotplug(const void *blob, unsigned *wait_ms) +{ + const int MAX_TRIES = 10; + static int num_tries; + + /* Check HPD. If it's high, we're all good. */ + if (fdtdec_get_gpio(&local.dp_hpd)) { + *wait_ms = 0; + return 0; + } + + debug("%s: eDP bridge failed to come up; try %d of %d\n", __func__, + num_tries, MAX_TRIES); + /* Immediately go into bridge reset if the hp line is not high */ + *wait_ms = 0; + ++num_tries; + return num_tries <= MAX_TRIES ? -EAGAIN : -ENODEV; +} + +#ifdef CONFIG_TPS65090_POWER +int board_dp_backlight_vdd(const void *blob, unsigned *wait_ms) +{ + /* This delay is T5 in the LCD timing spec (defined as > 10ms) */ + *wait_ms = 10; + return tps65090_fet_enable(1); /* Enable FET1, backlight */ +} +#endif + +int board_dp_backlight_pwm(const void *blob, unsigned *wait_ms) +{ + /* + * Configure backlight PWM as a simple output high (100% brightness) + * TODO(hatim.rv@samsung.com): Move to FDT + */ + gpio_direction_output(GPIO_B20, 1); + /* This delay is T6 in the LCD timing spec (defined as > 10ms) */ + *wait_ms = 10; + return 0; +} + +int board_dp_backlight_en(const void *blob, unsigned *wait_ms) +{ + /* + * Configure GPIO for LCD_BL_EN + * TODO(hatim.rv@samsung.com): Move to FDT + */ + gpio_direction_output(GPIO_X30, 1); + /* We're done, no more delays! */ + *wait_ms = 0; + return 0; +} + +static void board_enable_audio_codec(void) +{ + int node, ret, value; + struct fdt_gpio_state en_gpio; + + node = fdtdec_next_compatible(gd->fdt_blob, 0, + COMPAT_SAMSUNG_EXYNOS_SOUND); + if (node <= 0) + return; + + ret = fdtdec_decode_gpio(gd->fdt_blob, node, "codec-enable-gpio", + &en_gpio); + if (ret == -FDT_ERR_NOTFOUND) + return; + + /* Turn on the GPIO which connects to the codec's "enable" line. */ + value = (en_gpio.flags & FDT_GPIO_ACTIVE_LOW) ? 0 : 1; + gpio_direction_output(en_gpio.gpio, value); + gpio_set_pull(en_gpio.gpio, EXYNOS_GPIO_PULL_NONE); +} + +int board_init(void) +{ + struct fdt_memory mem_config; + + /* Record the time we spent before SPL */ + bootstage_add_record(BOOTSTAGE_ID_START_SPL, "spl_start", 0, + CONFIG_SPL_TIME_US); + bootstage_mark_name(BOOTSTAGE_ID_BOARD_INIT, "board_init"); + + if (fdtdec_decode_memory(gd->fdt_blob, &mem_config)) { + debug("%s: Failed to decode memory\n", __func__); + return -1; + } + + gd->bd->bi_boot_params = mem_config.start + 0x100UL; + +#ifdef CONFIG_OF_CONTROL + gd->bd->bi_arch_number = fdtdec_get_config_int(gd->fdt_blob, + "machine-arch-id", -1); + if (gd->bd->bi_arch_number == -1U) + debug("Warning: No /config/machine-arch-id defined in fdt\n"); +#endif +#ifdef CONFIG_EXYNOS_SPI + spi_init(); +#endif + + if (board_i2c_arb_init(gd->fdt_blob)) + return -1; + + board_i2c_init(gd->fdt_blob); + +#ifdef CONFIG_TPS65090_POWER + tps65090_init(); + + /* + * If we just reset, disable the backlight and lcd fets before + * [re-]initializing the lcd. This ensures we are always in the same + * state during lcd init. We've seen some oddities with these fets, so + * this removes a bit of uncertainty. + */ + if (board_is_processor_reset()) { + tps65090_fet_disable(1); + tps65090_fet_disable(6); + } +#endif + exynos_lcd_check_next_stage(gd->fdt_blob, 0); + + if (max77686_enable_32khz_cp()) { + debug("%s: Failed to enable max77686 32khz coprocessor clock\n", + __func__); + return -1; + } + +#if defined CONFIG_EXYNOS_CPUFREQ + if (exynos5250_cpufreq_init(gd->fdt_blob)) { + debug("%s: Failed to init CPU frequency scaling\n", __func__); + return -1; + } +#endif + +#if defined CONFIG_EXYNOS_TMU + if (tmu_init(gd->fdt_blob)) { + debug("%s: Failed to init TMU\n", __func__); + return -1; + } +#endif + + /* Clock Gating all the unused IP's to save power */ + clock_gate(); + + /* Disable USB3.0 PLL to save 250mW of power */ + disable_usb30_pll(); + + if (board_init_mkbp_devices(gd->fdt_blob)) + return -1; + + board_enable_audio_codec(); + + exynos_lcd_check_next_stage(gd->fdt_blob, 0); + + bootstage_mark_name(BOOTSTAGE_ID_BOARD_INIT_DONE, "board_init_done"); + + return 0; +} + +int dram_init(void) +{ + struct fdt_memory mem_config; + + if (fdtdec_decode_memory(gd->fdt_blob, &mem_config)) { + debug("%s: Failed to decode memory\n", __func__); + return -1; + } + + gd->ram_size = get_ram_size((long *)mem_config.start, + mem_config.end); + return 0; +} + +void dram_init_banksize(void) +{ + struct fdt_memory mem_config; + + if (fdtdec_decode_memory(gd->fdt_blob, &mem_config)) { + debug("%s: Failed to decode memory\n", __func__); + return; + } + + gd->bd->bi_dram[0].start = mem_config.start; + gd->bd->bi_dram[0].size = get_ram_size((long *)mem_config.start, + mem_config.end); +} + +int board_get_revision(void) +{ + struct fdt_gpio_state gpios[CONFIG_BOARD_REV_GPIO_COUNT]; + unsigned gpio_list[CONFIG_BOARD_REV_GPIO_COUNT]; + int board_rev = -1; + int count = 0; + int node; + + node = fdtdec_next_compatible(gd->fdt_blob, 0, + COMPAT_GOOGLE_BOARD_REV); + if (node >= 0) { + count = fdtdec_decode_gpios(gd->fdt_blob, node, + "google,board-rev-gpios", gpios, + CONFIG_BOARD_REV_GPIO_COUNT); + } + if (count > 0) { + int i; + + for (i = 0; i < count; i++) + gpio_list[i] = gpios[i].gpio; + board_rev = gpio_decode_number(gpio_list, count); + } else { + debug("%s: No board revision information in fdt\n", __func__); + } + + return board_rev; +} + +#ifdef CONFIG_DISPLAY_BOARDINFO +int checkboard(void) +{ +#ifdef CONFIG_OF_CONTROL + const char *board_name; + + board_name = fdt_getprop(gd->fdt_blob, 0, "model", NULL); + printf("\nBoard: %s, rev %d\n", board_name ? board_name : "<unknown>", + board_get_revision()); +#else + printf("\nBoard: SMDK5250\n"); +#endif + + return 0; +} +#endif + +#ifdef CONFIG_GENERIC_MMC +int board_mmc_getcd(struct mmc *mmc) +{ + struct mshci_host *host = mmc->priv; + int present = 1; /* for ch0 (eMMC) card is always present */ + + if (host->peripheral == PERIPH_ID_SDMMC2) + present = !readl(&host->reg->cdetect); + + return present; +} + +int board_mmc_init(bd_t *bis) +{ +#ifdef CONFIG_S5P_MSHCI + s5p_mshci_init(gd->fdt_blob); +#endif + return 0; +} +#endif + +#ifdef CONFIG_BOARD_EARLY_INIT_F +int board_early_init_f(void) +{ + exynos_pinmux_config(EXYNOS_UART, PINMUX_FLAG_NONE); + return 0; +} +#endif + +void board_i2c_release_bus(int node) +{ + /* If this is us, release the bus */ + if (node == local.arbitrate_node) { + gpio_set_value(local.ap_claim.gpio, 1); + udelay(local.slew_delay_us); + } +} + +int board_i2c_claim_bus(int node) +{ + unsigned start; + + if (node != local.arbitrate_node) + return 0; + +// putc('c'); + + /* Start a round of trying to claim the bus */ + start = get_timer(0); + do { + unsigned start_retry; + int waiting = 0; + + /* Indicate that we want to claim the bus */ + gpio_set_value(local.ap_claim.gpio, 0); + udelay(local.slew_delay_us); + + /* Wait for the EC to release it */ + start_retry = get_timer(0); + while (get_timer(start_retry) < local.wait_retry_ms) { + if (gpio_get_value(local.ec_claim.gpio)) { + /* We got it, so return */ + return 0; + } + + if (!waiting) { + waiting = 1; + } + } + + /* It didn't release, so give up, wait, and try again */ + gpio_set_value(local.ap_claim.gpio, 1); + + mdelay(local.wait_retry_ms); + } while (get_timer(start) < local.wait_free_ms); + + /* Give up, release our claim */ + printf("I2C: Could not claim bus, timeout %lu\n", get_timer(start)); + + return -1; +} + +#ifdef CONFIG_SATA_AHCI +int sata_initialize(void) +{ + return exynos5_sata_init(gd->fdt_blob); +} +#endif + +#ifdef CONFIG_BOARD_LATE_INIT +int board_late_init(void) +{ + stdio_print_current_devices(); + + return 0; +} +#endif + +#endif /* big #if */ +#if 0 +/* ACPI */ +void mainboard_suspend_resume(void) +{ + /* FIXME: stub */ + return; +} +#endif + +static void mainboard_init(device_t dev) +{ + /* FIXME: stub */ + return; +} + +// mainboard_enable is executed as first thing after +// enumerate_buses(). + +static void mainboard_enable(device_t dev) +{ + dev->ops->init = mainboard_init; +} + +struct chip_operations mainboard_ops = { + .name = "Samsung/Google ChromeBook", + .enable_dev = mainboard_enable, +}; + diff --git a/src/mainboard/google/snow/romstage.c b/src/mainboard/google/snow/romstage.c new file mode 100644 index 0000000..040309f --- /dev/null +++ b/src/mainboard/google/snow/romstage.c @@ -0,0 +1,289 @@ +/* + * This file is part of the coreboot project. + * + * Copyright (C) 2007-2010 coresystems GmbH + * Copyright (C) 2011 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 + */ + +#if 0 +#include <stdint.h> +#include <string.h> +#include <lib.h> +#include <timestamp.h> +#include <arch/io.h> +//#include <arch/romcc_io.h> +#if 0 +#include <device/pci_def.h> +#include <device/pnp_def.h> +#include <cpu/x86/lapic.h> +#include <pc80/mc146818rtc.h> +#endif +#include <cbfs.h> +#include <cbmem.h> +#include <console/console.h> +#if 0 +#include "northbridge/intel/sandybridge/sandybridge.h" +#include "northbridge/intel/sandybridge/raminit.h" +#include "southbridge/intel/bd82x6x/pch.h" +#include "southbridge/intel/bd82x6x/gpio.h" +#endif +#include <arch/cpu.h> +#if 0 +#include <cpu/x86/bist.h> +#include <cpu/x86/msr.h> +#endif +#include "option_table.h" +#include "gpio.h" +#if CONFIG_CONSOLE_SERIAL8250 +#if 0 +#include "superio/smsc/lpc47n207/lpc47n207.h" +#include "superio/smsc/lpc47n207/early_serial.c" +#endif +#endif +#if CONFIG_CHROMEOS +#include <vendorcode/google/chromeos/chromeos.h> +#endif +#endif +#include <cache.h> + +static void mmu_setup(void) +{ + dram_bank_mmu_setup(CONFIG_SYS_SDRAM_BASE, CONFIG_DRAM_SIZE_MB * 1024); +} + +void main(unsigned long bist) +{ + mmu_setup(); +} + +#if 0 +/* FIXME: This is based off lumpy's romstage.c main() and is gutted to + resemble snow's eventually... */ +void main(unsigned long bist) +{ + int boot_mode = 0; + int cbmem_was_initted; +// u32 pm1_cnt; +// u16 pm1_sts; + +#if CONFIG_COLLECT_TIMESTAMPS +#if 0 + tsc_t start_romstage_time; + tsc_t before_dram_time; + tsc_t after_dram_time; + tsc_t base_time = { + .lo = pci_read_config32(PCI_DEV(0, 0x00, 0), 0xdc), + .hi = pci_read_config32(PCI_DEV(0, 0x1f, 2), 0xd0) + }; +#endif +#endif + +#if 0 + typedef const uint8_t spd_blob[256]; + struct cbfs_file *spd_file; + spd_blob *spd_data; +#endif + + +#if CONFIG_COLLECT_TIMESTAMPS +// start_romstage_time = rdtsc(); +#endif + +#if 0 + if (bist == 0) + enable_lapic(); + + pch_enable_lpc(); + + /* Enable GPIOs */ + pci_write_config32(PCH_LPC_DEV, GPIO_BASE, DEFAULT_GPIOBASE|1); + pci_write_config8(PCH_LPC_DEV, GPIO_CNTL, 0x10); + setup_pch_gpios(&lumpy_gpio_map); + + console_init(); +#endif + +#if CONFIG_CHROMEOS + save_chromeos_gpios(); +#endif + +#if 0 + /* Halt if there was a built in self test failure */ + report_bist_failure(bist); +#endif + +#if 0 + /* Perform some early chipset initialization required + * before RAM initialization can work + */ + sandybridge_early_initialization(SANDYBRIDGE_MOBILE); + printk(BIOS_DEBUG, "Back from sandybridge_early_initialization()\n"); + + /* Check PM1_STS[15] to see if we are waking from Sx */ + pm1_sts = inw(DEFAULT_PMBASE + PM1_STS); + + /* Read PM1_CNT[12:10] to determine which Sx state */ + pm1_cnt = inl(DEFAULT_PMBASE + PM1_CNT); +#endif +#if 0 + + if ((pm1_sts & WAK_STS) && ((pm1_cnt >> 10) & 7) == 5) { +#if CONFIG_HAVE_ACPI_RESUME + printk(BIOS_DEBUG, "Resume from S3 detected.\n"); + boot_mode = 2; + /* Clear SLP_TYPE. This will break stage2 but + * we care for that when we get there. + */ + outl(pm1_cnt & ~(7 << 10), DEFAULT_PMBASE + PM1_CNT); +#else + printk(BIOS_DEBUG, "Resume from S3 detected, but disabled.\n"); +#endif + } +#endif + +// post_code(0x38); + /* Enable SPD ROMs and DDR-III DRAM */ +// enable_smbus(); + +#if 0 + /* Prepare USB controller early in S3 resume */ + if (boot_mode == 2) + enable_usb_bar(); + + u32 gp_lvl2 = inl(DEFAULT_GPIOBASE + 0x38); + u8 gpio33, gpio41, gpio49; + gpio33 = (gp_lvl2 >> (33-32)) & 1; + gpio41 = (gp_lvl2 >> (41-32)) & 1; + gpio49 = (gp_lvl2 >> (49-32)) & 1; + printk(BIOS_DEBUG, "Memory Straps:\n"); + printk(BIOS_DEBUG, " - memory capacity %dGB\n", + gpio33 ? 2 : 1); + printk(BIOS_DEBUG, " - die revision %d\n", + gpio41 ? 2 : 1); + printk(BIOS_DEBUG, " - vendor %s\n", + gpio49 ? "Samsung" : "Other"); + + int spd_index = 0; + + switch ((gpio49 << 2) | (gpio41 << 1) | gpio33) { + case 0: // Other 1G Rev 1 + spd_index = 0; + break; + case 2: // Other 1G Rev 2 + spd_index = 1; + break; + case 1: // Other 2G Rev 1 + case 3: // Other 2G Rev 2 + spd_index = 2; + break; + case 4: // Samsung 1G Rev 1 + spd_index = 3; + break; + case 6: // Samsung 1G Rev 2 + spd_index = 4; + break; + case 5: // Samsung 2G Rev 1 + case 7: // Samsung 2G Rev 2 + spd_index = 5; + break; + } + + spd_file = cbfs_find("spd.bin"); + if (!spd_file) + die("SPD data not found."); + if (spd_file->len < (spd_index + 1) * 256) + die("Missing SPD data."); + spd_data = (spd_blob *)CBFS_SUBHEADER(spd_file); + // leave onboard dimm address at f0, and copy spd data there. + memcpy(pei_data.spd_data[0], spd_data[spd_index], 256); + + post_code(0x39); + pei_data.boot_mode = boot_mode; +#endif +#if CONFIG_COLLECT_TIMESTAMPS + before_dram_time = rdtsc(); +#endif + sdram_initialize(&pei_data); + +#if CONFIG_COLLECT_TIMESTAMPS + after_dram_time = rdtsc(); +#endif +#if 0 + post_code(0x3a); + /* Perform some initialization that must run before stage2 */ + early_pch_init(); + post_code(0x3b); + + rcba_config(); + post_code(0x3c); + + quick_ram_check(); + post_code(0x3e); + + MCHBAR16(SSKPD) = 0xCAFE; +#endif +#if CONFIG_EARLY_CBMEM_INIT + cbmem_was_initted = !cbmem_initialize(); +#else + cbmem_was_initted = cbmem_reinit((uint64_t) (get_top_of_ram() + - HIGH_MEMORY_SIZE)); +#endif + +#if 0 +#if CONFIG_HAVE_ACPI_RESUME + /* If there is no high memory area, we didn't boot before, so + * this is not a resume. In that case we just create the cbmem toc. + */ + + *(u32 *)CBMEM_BOOT_MODE = 0; + *(u32 *)CBMEM_RESUME_BACKUP = 0; + + if ((boot_mode == 2) && cbmem_was_initted) { + void *resume_backup_memory = cbmem_find(CBMEM_ID_RESUME); + if (resume_backup_memory) { + *(u32 *)CBMEM_BOOT_MODE = boot_mode; + *(u32 *)CBMEM_RESUME_BACKUP = (u32)resume_backup_memory; + } + /* Magic for S3 resume */ + pci_write_config32(PCI_DEV(0, 0x00, 0), SKPAD, 0xcafed00d); + } else if (boot_mode == 2) { + /* Failed S3 resume, reset to come up cleanly */ + outb(0x6, 0xcf9); + hlt(); + } else { + pci_write_config32(PCI_DEV(0, 0x00, 0), SKPAD, 0xcafebabe); + } +#endif +#endif +// post_code(0x3f); +#if CONFIG_CHROMEOS + init_chromeos(boot_mode); +#endif +#if 0 +#if CONFIG_COLLECT_TIMESTAMPS + timestamp_init(base_time); + timestamp_add(TS_START_ROMSTAGE, start_romstage_time ); + timestamp_add(TS_BEFORE_INITRAM, before_dram_time ); + timestamp_add(TS_AFTER_INITRAM, after_dram_time ); + timestamp_add_now(TS_END_ROMSTAGE); +#endif +#endif +#if CONFIG_CONSOLE_CBMEM + /* Keep this the last thing this function does. */ + cbmemc_reinit(); +#endif +} +#endif diff --git a/src/mainboard/google/snow/smdk5250_spl.c b/src/mainboard/google/snow/smdk5250_spl.c new file mode 100644 index 0000000..372dd3b --- /dev/null +++ b/src/mainboard/google/snow/smdk5250_spl.c @@ -0,0 +1,123 @@ +/* + * Copyright (c) 2012 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 + */ + +#if 0 +#include <common.h> +#include <asm/gpio.h> +#include <asm/arch-exynos/cpu.h> +#include <asm/arch/board.h> +#include <asm/arch/dmc.h> +#endif + +#include <arch/gpio.h> +#include <cpu/samsung/exynos-common/spl.h> +#include <cpu/samsung/exynos5250/gpio.h> + +#define SIGNATURE 0xdeadbeef + +/* Parameters of early board initialization in SPL */ +static struct spl_machine_param machine_param + __attribute__((section(".machine_param"))) = { + .signature = SIGNATURE, + .version = 1, + .params = "vmubfasirMw", + .size = sizeof(machine_param), + + .mem_iv_size = 0x1f, + .mem_type = DDR_MODE_DDR3, + + /* + * Set uboot_size to 0x100000 bytes. + * + * This is an overly conservative value chosen to accommodate all + * possible U-Boot image. You are advised to set this value to a + * smaller realistic size via scripts that modifies the .machine_param + * section of output U-Boot image. + */ + .uboot_size = 0x100000, + + .boot_source = BOOT_MODE_OM, + .frequency_mhz = 800, + .arm_freq_mhz = 1700, + .serial_base = 0x12c30000, + .i2c_base = 0x12c60000, + .board_rev_gpios = GPIO_D00 | (GPIO_D01 << 16), + .mem_manuf = MEM_MANUF_SAMSUNG, + .bad_wake_gpio = GPIO_Y10, +}; + +struct spl_machine_param *spl_get_machine_params(void) +{ + if (machine_param.signature != SIGNATURE) { + /* TODO: Call panic() here */ + while (1) + ; + } + + return &machine_param; +} + +/* FIXME(dhendrix): Move all this board_* stuff into the actual mainboard + * directory. */ +#if 0 +/* FIXME(dhendrix): originally this #define was in exynos5-common.h which + seems wrong. */ +#define CONFIG_BOARD_REV_GPIO_COUNT 2 +int board_get_revision(void) +{ + struct spl_machine_param *params = spl_get_machine_params(); + unsigned gpio[CONFIG_BOARD_REV_GPIO_COUNT]; + + gpio[0] = params->board_rev_gpios & 0xffff; + gpio[1] = params->board_rev_gpios >> 16; + return gpio_decode_number(gpio, CONFIG_BOARD_REV_GPIO_COUNT); +} +#endif + +int board_wakeup_permitted(void) +{ + struct spl_machine_param *param = spl_get_machine_params(); + const int gpio = param->bad_wake_gpio; + int is_bad_wake; + + /* We're a bad wakeup if the gpio was defined and was high */ + is_bad_wake = ((gpio != -1) && gpio_get_value(gpio)); + + return !is_bad_wake; +} + +#if 0 +/* + * TODO(sjg@chromium.org): + * Declared there here for SPL, since there is no core i2c subsystem and + * cmd_i2c.c is not included. + */ +void board_i2c_release_bus(int node) +{ +} + +int board_i2c_claim_bus(int node) +{ + /* EC is not allowed to touch the bus until we enter U-Boot */ + return 0; +} +#endif