armv7: Move Exynos from 'cpu' to 'soc'.
The Exynos family and most ARM products are SoC, not just CPU.
We used to put ARM code in src/cpu to avoid polluting the code base for what was
essentially an experiment at the time. Now that it's past the experimental phase
and we're going to see more SoCs (including intel/baytrail) in coreboot.
Change-Id: I5ea1f822664244edf5f77087bc8018d7c535f81c
Reviewed-on: https://chromium-review.googlesource.com/170891
Tested-by: Hung-Te Lin <hungte@chromium.org>
Reviewed-by: Aaron Durbin <adurbin@chromium.org>
Reviewed-by: Ronald Minnich <rminnich@chromium.org>
Commit-Queue: Hung-Te Lin <hungte@chromium.org>
(cherry picked from commit c8bb8fe0b20be37465f93c738d80e7e43033670a)
Signed-off-by: Isaac Christensen <isaac.christensen@se-eng.com>
Reviewed-on: http://review.coreboot.org/6739
Tested-by: build bot (Jenkins)
Reviewed-by: Ronald G. Minnich <rminnich@gmail.com>
diff --git a/src/soc/samsung/exynos5250/Kconfig b/src/soc/samsung/exynos5250/Kconfig
new file mode 100644
index 0000000..2b4ad39
--- /dev/null
+++ b/src/soc/samsung/exynos5250/Kconfig
@@ -0,0 +1,89 @@
+config CPU_SAMSUNG_EXYNOS5250
+ select ARCH_BOOTBLOCK_ARMV7
+ select ARCH_ROMSTAGE_ARMV7
+ select ARCH_RAMSTAGE_ARMV7
+ select CPU_HAS_BOOTBLOCK_INIT
+ select HAVE_MONOTONIC_TIMER
+ select HAVE_UART_SPECIAL
+ select DYNAMIC_CBMEM
+ bool
+ default n
+
+if CPU_SAMSUNG_EXYNOS5250
+
+# ROM image layout.
+#
+# 0x0000: vendor-provided BL1 (8k).
+# 0x2000: bootblock
+# 0x2010-0x2090: reserved for CBFS master header.
+# 0xA000: Free for CBFS data.
+
+config BOOTBLOCK_ROM_OFFSET
+ hex
+ default 0x2000
+
+config CBFS_HEADER_ROM_OFFSET
+ hex "offset of master CBFS header in ROM"
+ default 0x2010
+
+config CBFS_ROM_OFFSET
+ # Calculated by BOOTBLOCK_ROM_OFFSET + max bootblock size.
+ hex "offset of CBFS data in ROM"
+ default 0x0A000
+
+config SYS_SDRAM_BASE
+ hex
+ default 0x40000000
+
+# Example SRAM/iRAM map for Exynos5250 platform:
+#
+# 0x0202_0000: vendor-provided BL1
+# 0x0202_3400: bootblock, assume up to 32KB in size
+# 0x0203_0000: romstage, assume up to 128KB in size.
+# 0x0207_8000: stack pointer
+
+config BOOTBLOCK_BASE
+ hex
+ default 0x02023400
+
+config ROMSTAGE_BASE
+ hex
+ default 0x02030000
+
+config RAMSTAGE_BASE
+ hex
+ default SYS_SDRAM_BASE
+
+# Stack may reside in either IRAM or DRAM. We will define it to live
+# at the top of IRAM for now.
+#
+# Stack grows downward, push operation stores register contents in
+# consecutive memory locations ending just below SP
+config STACK_TOP
+ hex
+ default 0x02078000
+
+config STACK_BOTTOM
+ hex
+ default 0x02074000
+
+config STACK_SIZE
+ hex
+ default 0x4000
+
+# TODO We may probably move this to board-specific implementation files instead
+# of KConfig values.
+config CBFS_CACHE_ADDRESS
+ hex "memory address to put CBFS cache data"
+ default 0x0205c000
+
+config CBFS_CACHE_SIZE
+ hex "size of CBFS cache data"
+ default 0x00018000
+
+# TTB needs to be aligned to 16KB.
+config TTB_BUFFER
+ hex "memory address of the TTB buffer"
+ default 0x02058000
+
+endif
diff --git a/src/soc/samsung/exynos5250/Makefile.inc b/src/soc/samsung/exynos5250/Makefile.inc
new file mode 100644
index 0000000..a15bc9c
--- /dev/null
+++ b/src/soc/samsung/exynos5250/Makefile.inc
@@ -0,0 +1,62 @@
+bootblock-y += spi.c alternate_cbfs.c
+bootblock-y += bootblock.c
+bootblock-y += pinmux.c mct.c power.c
+# Clock is required for UART
+bootblock-$(CONFIG_BOOTBLOCK_CONSOLE) += clock_init.c
+bootblock-$(CONFIG_BOOTBLOCK_CONSOLE) += clock.c
+bootblock-$(CONFIG_BOOTBLOCK_CONSOLE) += monotonic_timer.c
+ifeq ($(CONFIG_DRIVERS_UART),y)
+bootblock-$(CONFIG_BOOTBLOCK_CONSOLE) += uart.c
+endif
+bootblock-y += wakeup.c
+bootblock-y += gpio.c
+bootblock-$(CONFIG_BOOTBLOCK_CONSOLE) += timer.c
+
+romstage-y += spi.c alternate_cbfs.c
+romstage-y += clock.c
+romstage-y += clock_init.c
+romstage-y += pinmux.c # required by s3c24x0_i2c and uart.
+romstage-y += dmc_common.c
+romstage-y += dmc_init_ddr3.c
+romstage-y += power.c
+romstage-y += mct.c
+romstage-y += monotonic_timer.c
+ifeq ($(CONFIG_DRIVERS_UART),y)
+romstage-y += uart.c
+endif
+romstage-y += wakeup.c
+romstage-y += gpio.c
+romstage-y += timer.c
+romstage-y += trustzone.c
+romstage-y += i2c.c
+#romstage-y += wdt.c
+romstage-y += cbmem.c
+
+ramstage-y += spi.c alternate_cbfs.c
+ramstage-y += clock.c
+ramstage-y += clock_init.c
+ramstage-y += pinmux.c
+ramstage-y += power.c
+ramstage-$(CONFIG_DRIVERS_UART) += uart.c
+ramstage-y += cpu.c
+ramstage-y += tmu.c
+ramstage-y += mct.c
+ramstage-y += monotonic_timer.c
+ramstage-y += timer.c
+ramstage-y += gpio.c
+ramstage-y += i2c.c
+ramstage-y += dp-reg.c
+ramstage-y += fb.c
+ramstage-y += usb.c
+ramstage-y += cbmem.c
+
+# Run an intermediate step when producing coreboot.rom
+# that adds additional components to the final firmware
+# image outside of CBFS
+.PHONY: exynos5250_add_bl1
+$(obj)/coreboot.rom: exynos5250_add_bl1
+exynos5250_add_bl1: $(obj)/coreboot.pre
+ printf " DD Adding Samsung Exynos5250 BL1\n"
+ # TODO(hungte) Change this 'cpu' to soc when build scripts are changed.
+ dd if=3rdparty/cpu/samsung/exynos5250/bl1.bin \
+ of=$(obj)/coreboot.pre conv=notrunc >/dev/null 2>&1
diff --git a/src/soc/samsung/exynos5250/alternate_cbfs.c b/src/soc/samsung/exynos5250/alternate_cbfs.c
new file mode 100644
index 0000000..10b33f0
--- /dev/null
+++ b/src/soc/samsung/exynos5250/alternate_cbfs.c
@@ -0,0 +1,176 @@
+/*
+ * This file is part of the coreboot project.
+ *
+ * Copyright 2013 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 <assert.h>
+#include <cbfs.h> /* This driver serves as a CBFS media source. */
+#include <stdlib.h>
+#include <string.h>
+#include <console/console.h>
+#include "alternate_cbfs.h"
+#include "power.h"
+#include "spi.h"
+
+/* This allows USB A-A firmware upload from a compatible host in four parts:
+ * The first two are the bare BL1 and the Coreboot boot block, which are just
+ * written to their respective loading addresses. These transfers are initiated
+ * by the IROM / BL1, so this code has nothing to do with them.
+ *
+ * The third transfer is a valid CBFS image that contains only the romstage,
+ * and must be small enough to fit into alternate_cbfs_size[__BOOT_BLOCK__] in
+ * IRAM. It is loaded when this function gets called in the boot block, and
+ * the normal CBFS code extracts the romstage from it.
+ *
+ * The fourth transfer is also a CBFS image, but can be of arbitrary size and
+ * should contain all available stages/payloads/etc. It is loaded when this
+ * function is called a second time at the end of the romstage, and copied to
+ * alternate_cbfs_buffer[!__BOOT_BLOCK__] in DRAM. It will reside there for the
+ * rest of the firmware's lifetime and all subsequent stages (which will not
+ * have __PRE_RAM__ defined) can just directly reference it there.
+ */
+static int usb_cbfs_open(struct cbfs_media *media)
+{
+#ifdef __PRE_RAM__
+ static int first_run = 1;
+ int (*irom_load_usb)(void) = *irom_load_image_from_usb_ptr;
+
+ if (!first_run)
+ return 0;
+
+ if (!irom_load_usb()) {
+ printk(BIOS_EMERG, "Unable to load CBFS image via USB!\n");
+ return -1;
+ }
+
+ /*
+ * We need to trust the host/irom to copy the image to our
+ * alternate_cbfs_buffer address... there is no way to control or even
+ * check the transfer size or target address from our side.
+ */
+
+ printk(BIOS_DEBUG, "USB A-A transfer successful, CBFS image should now"
+ " be at %p\n", alternate_cbfs_buffer);
+ first_run = 0;
+#endif
+ return 0;
+}
+
+/*
+ * SDMMC works very similar to USB A-A: we copy the CBFS image into memory
+ * and read it from there. While SDMMC would also allow direct block by block
+ * on-demand reading, we might run into problems if we call back into the IROM
+ * in very late boot stages (e.g. after initializing/changing MMC clocks)... so
+ * this seems like a safer approach. It also makes it easy to pass our image
+ * down to payloads.
+ */
+static int sdmmc_cbfs_open(struct cbfs_media *media)
+{
+#ifdef __PRE_RAM__
+ /*
+ * In the bootblock, we just copy the small part that fits in the buffer
+ * and hope that it's enough (since the romstage is currently always the
+ * first component in the image, this should work out). In the romstage,
+ * we copy until our buffer is full (currently 12M) to avoid the pain of
+ * figuring out the true image size from in here. Since this is mainly a
+ * developer/debug boot mode, those shortcomings should be bearable.
+ */
+ const u32 count = alternate_cbfs_size / 512;
+ static int first_run = 1;
+ int (*irom_load_sdmmc)(u32 start, u32 count, void *dst) =
+ *irom_sdmmc_read_blocks_ptr;
+
+ if (!first_run)
+ return 0;
+
+ if (!irom_load_sdmmc(1, count, alternate_cbfs_buffer)) {
+ printk(BIOS_EMERG, "Unable to load CBFS image from SDMMC!\n");
+ return -1;
+ }
+
+ printk(BIOS_DEBUG, "SDMMC read successful, CBFS image should now be"
+ " at %p\n", alternate_cbfs_buffer);
+ first_run = 0;
+#endif
+ return 0;
+}
+
+static int alternate_cbfs_close(struct cbfs_media *media) { return 0; }
+
+static size_t alternate_cbfs_read(struct cbfs_media *media, void *dest,
+ size_t offset, size_t count)
+{
+ ASSERT(offset + count < alternate_cbfs_size);
+ memcpy(dest, alternate_cbfs_buffer + offset, count);
+ return count;
+}
+
+static void *alternate_cbfs_map(struct cbfs_media *media, size_t offset,
+ size_t count)
+{
+ ASSERT(offset + count < alternate_cbfs_size);
+ return alternate_cbfs_buffer + offset;
+}
+
+static void *alternate_cbfs_unmap(struct cbfs_media *media,
+ const void *buffer) { return 0; }
+
+static int initialize_exynos_sdmmc_cbfs_media(struct cbfs_media *media)
+{
+ printk(BIOS_DEBUG, "Using Exynos alternate boot mode SDMMC\n");
+
+ media->open = sdmmc_cbfs_open;
+ media->close = alternate_cbfs_close;
+ media->read = alternate_cbfs_read;
+ media->map = alternate_cbfs_map;
+ media->unmap = alternate_cbfs_unmap;
+
+ return 0;
+}
+
+static int initialize_exynos_usb_cbfs_media(struct cbfs_media *media)
+{
+ printk(BIOS_DEBUG, "Using Exynos alternate boot mode USB A-A\n");
+
+ media->open = usb_cbfs_open;
+ media->close = alternate_cbfs_close;
+ media->read = alternate_cbfs_read;
+ media->map = alternate_cbfs_map;
+ media->unmap = alternate_cbfs_unmap;
+
+ return 0;
+}
+
+int init_default_cbfs_media(struct cbfs_media *media)
+{
+ if (*iram_secondary_base == SECONDARY_BASE_BOOT_USB)
+ return initialize_exynos_usb_cbfs_media(media);
+
+ switch (exynos_power->om_stat & OM_STAT_MASK) {
+ case OM_STAT_SDMMC:
+ return initialize_exynos_sdmmc_cbfs_media(media);
+ case OM_STAT_SPI:
+ return initialize_exynos_spi_cbfs_media(media,
+ (void*)CONFIG_CBFS_CACHE_ADDRESS,
+ CONFIG_CBFS_CACHE_SIZE);
+ default:
+ printk(BIOS_EMERG, "Exynos OM_STAT value 0x%x not supported!\n",
+ exynos_power->om_stat);
+ return 0;
+ }
+}
diff --git a/src/soc/samsung/exynos5250/alternate_cbfs.h b/src/soc/samsung/exynos5250/alternate_cbfs.h
new file mode 100644
index 0000000..72a30ac
--- /dev/null
+++ b/src/soc/samsung/exynos5250/alternate_cbfs.h
@@ -0,0 +1,51 @@
+/*
+ * This file is part of the coreboot project.
+ *
+ * Copyright 2013 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
+ */
+
+#ifndef CPU_SAMSUNG_EXYNOS5250_ALTERNATE_CBFS_H
+#define CPU_SAMSUNG_EXYNOS5250_ALTERNATE_CBFS_H
+
+/* These are pointers to function pointers. Double indirection! */
+static void * * const irom_sdmmc_read_blocks_ptr = (void * *)0x02020030;
+static void * * const irom_msh_read_from_fifo_emmc_ptr = (void * *)0x02020044;
+static void * * const irom_msh_end_boot_op_emmc_ptr = (void * *)0x02020048;
+static void * * const irom_spi_sf_read_ptr = (void * *)0x02020058;
+static void * * const irom_load_image_from_usb_ptr = (void * *)0x02020070;
+
+#define SECONDARY_BASE_BOOT_USB 0xfeed0002
+static u32 * const iram_secondary_base = (u32 *)0x02020018;
+
+/* Values pulled from U-Boot, I think the manual is wrong here (for SPI) */
+#define OM_STAT_SDMMC 0x4
+#define OM_STAT_EMMC 0x8
+#define OM_STAT_SPI 0x14
+#define OM_STAT_MASK 0x7f
+
+#if defined(__BOOT_BLOCK__)
+ /* A small space in IRAM to hold the romstage-only image */
+ static void * const alternate_cbfs_buffer =
+ (void *)CONFIG_CBFS_CACHE_ADDRESS;
+ static size_t const alternate_cbfs_size = CONFIG_CBFS_CACHE_SIZE;
+#else
+ /* Just put this anywhere in RAM that's far enough from anything else */
+ /* TODO: Find a better way to "reserve" this region? */
+ static void * const alternate_cbfs_buffer = (void *)0x77400000;
+ static size_t const alternate_cbfs_size = 0xc00000;
+#endif
+
+#endif
diff --git a/src/soc/samsung/exynos5250/bootblock.c b/src/soc/samsung/exynos5250/bootblock.c
new file mode 100644
index 0000000..f524399
--- /dev/null
+++ b/src/soc/samsung/exynos5250/bootblock.c
@@ -0,0 +1,41 @@
+/*
+ * This file is part of the coreboot project.
+ *
+ * Copyright 2013 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 "clk.h"
+#include "wakeup.h"
+
+void bootblock_cpu_init(void)
+{
+ /* kick off the multi-core timer.
+ * We want to do this as early as we can.
+ */
+ mct_start();
+
+ if (get_wakeup_state() == WAKEUP_DIRECT) {
+ wakeup();
+ /* Never returns. */
+ }
+
+ /* For most ARM systems, we have to initialize firmware media source
+ * (ex, SPI, SD/MMC, or eMMC) now; but for Exynos platform, that is
+ * already handled by iROM so there's no need to setup again.
+ */
+}
diff --git a/src/soc/samsung/exynos5250/cbmem.c b/src/soc/samsung/exynos5250/cbmem.c
new file mode 100644
index 0000000..4650320
--- /dev/null
+++ b/src/soc/samsung/exynos5250/cbmem.c
@@ -0,0 +1,27 @@
+/*
+ * This file is part of the coreboot project.
+ *
+ * Copyright 2013 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 <stddef.h>
+#include <cbmem.h>
+#include "cpu.h"
+
+void *cbmem_top(void)
+{
+ return (void *)(get_fb_base_kb() * KiB);
+}
diff --git a/src/soc/samsung/exynos5250/chip.h b/src/soc/samsung/exynos5250/chip.h
new file mode 100644
index 0000000..242bd21
--- /dev/null
+++ b/src/soc/samsung/exynos5250/chip.h
@@ -0,0 +1,45 @@
+/*
+ * This file is part of the coreboot project.
+ *
+ * Copyright 2013 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
+ */
+
+#ifndef CPU_SAMSUNG_EXYNOS5250_H
+#define CPU_SAMSUNG_EXYNOS5250_H
+
+#include "gpio.h"
+
+struct soc_samsung_exynos5250_config {
+ /* special magic numbers! */
+ int clkval_f;
+ int upper_margin;
+ int lower_margin;
+ int vsync;
+ int left_margin;
+ int right_margin;
+ int hsync;
+
+ int xres;
+ int yres;
+ int framebuffer_bits_per_pixel;
+
+ int usb_vbus_gpio;
+ int usb_hsic_gpio;
+
+ u32 lcdbase;
+};
+
+#endif /* CPU_SAMSUNG_EXYNOS5250_H */
diff --git a/src/soc/samsung/exynos5250/clk.h b/src/soc/samsung/exynos5250/clk.h
new file mode 100644
index 0000000..f09ac41
--- /dev/null
+++ b/src/soc/samsung/exynos5250/clk.h
@@ -0,0 +1,629 @@
+/*
+ * This file is part of the coreboot project.
+ *
+ * Copyright 2013 Google Inc.
+ * 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; 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
+ */
+
+#ifndef CPU_SAMSUNG_EXYNOS5250_CLK_H
+#define CPU_SAMSUNG_EXYNOS5250_CLK_H
+
+#include <stdint.h>
+
+#include "cpu.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;
+};
+
+unsigned long get_pll_clk(int pllreg);
+unsigned long get_arm_clk(void);
+unsigned long get_pwm_clk(void);
+unsigned long get_uart_clk(int dev_index);
+void set_mmc_clk(int dev_index, unsigned int div);
+
+/**
+ * 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);
+
+#include "pinmux.h"
+
+
+#define MCT_HZ 24000000
+
+/*
+ * Set mshci controller instances clock divider
+ *
+ * @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);
+
+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];
+};
+
+static struct exynos5_clock * const exynos_clock = (void *)EXYNOS5_CLOCK_BASE;
+
+struct exynos5_mct {
+ 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;
+};
+
+static struct exynos5_mct * const exynos_mct =
+ (void *)EXYNOS5_MULTI_CORE_TIMER_BASE;
+
+#define EXYNOS5_EPLLCON0_LOCKED_SHIFT 29 /* EPLL Locked bit position*/
+#define EPLL_SRC_CLOCK 24000000 /*24 MHz Crystal 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);
+
+/* Clock gate unused IP */
+void clock_gate(void);
+
+void mct_start(void);
+uint64_t mct_raw_value(void);
+
+#include "dmc.h"
+
+/* These are the ratio's for configuring ARM clock */
+struct arm_clk_ratios {
+ unsigned int arm_freq_mhz; /* Frequency of ARM core in MHz */
+
+ unsigned int apll_mdiv;
+ unsigned int apll_pdiv;
+ unsigned int apll_sdiv;
+
+ unsigned int arm2_ratio;
+ unsigned int apll_ratio;
+ unsigned int pclk_dbg_ratio;
+ unsigned int atb_ratio;
+ unsigned int periph_ratio;
+ unsigned int acp_ratio;
+ unsigned int cpud_ratio;
+ unsigned int arm_ratio;
+};
+
+/**
+ * Get the clock ratios for CPU configuration
+ *
+ * @return pointer to the clock ratios that we should use
+ */
+struct arm_clk_ratios *get_arm_clk_ratios(void);
+
+/*
+ * Initialize clock for the device
+ */
+struct mem_timings;
+void system_clock_init(struct mem_timings *mem,
+ struct arm_clk_ratios *arm_clk_ratio);
+
+#endif
diff --git a/src/soc/samsung/exynos5250/clock.c b/src/soc/samsung/exynos5250/clock.c
new file mode 100644
index 0000000..8a731be
--- /dev/null
+++ b/src/soc/samsung/exynos5250/clock.c
@@ -0,0 +1,677 @@
+/*
+ * This file is part of the coreboot project.
+ *
+ * Copyright (C) 2010 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; 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 <assert.h>
+#include <stdlib.h>
+#include <arch/io.h>
+#include <console/console.h>
+#include "clk.h"
+#include "periph.h"
+#include "timer.h"
+
+/* input clock of PLL: SMDK5250 has 24MHz input clock */
+#define CONFIG_SYS_CLK_FREQ 24000000
+
+static 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,
+ }
+};
+
+/* 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 achieve 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)
+{
+ unsigned long r, m, p, s, k = 0, mask, fout;
+ unsigned int freq;
+
+ switch (pllreg) {
+ case APLL:
+ r = readl(&exynos_clock->apll_con0);
+ break;
+ case BPLL:
+ r = readl(&exynos_clock->bpll_con0);
+ break;
+ case MPLL:
+ r = readl(&exynos_clock->mpll_con0);
+ break;
+ case EPLL:
+ r = readl(&exynos_clock->epll_con0);
+ k = readl(&exynos_clock->epll_con1);
+ break;
+ case VPLL:
+ r = readl(&exynos_clock->vpll_con0);
+ k = readl(&exynos_clock->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 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(&exynos_clock->src_peric0);
+ div = readl(&exynos_clock->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(&exynos_clock->src_peric0);
+ div = readl(&exynos_clock->div_peric3);
+ break;
+ case PERIPH_ID_SPI0:
+ case PERIPH_ID_SPI1:
+ src = readl(&exynos_clock->src_peric1);
+ div = readl(&exynos_clock->div_peric1);
+ break;
+ case PERIPH_ID_SPI2:
+ src = readl(&exynos_clock->src_peric1);
+ div = readl(&exynos_clock->div_peric2);
+ break;
+ case PERIPH_ID_SPI3:
+ case PERIPH_ID_SPI4:
+ src = readl(&exynos_clock->sclk_src_isp);
+ div = readl(&exynos_clock->sclk_div_isp);
+ break;
+ case PERIPH_ID_SATA:
+ src = readl(&exynos_clock->src_fsys);
+ div = readl(&exynos_clock->div_fsys0);
+ break;
+ case PERIPH_ID_SDMMC0:
+ case PERIPH_ID_SDMMC1:
+ case PERIPH_ID_SDMMC2:
+ case PERIPH_ID_SDMMC3:
+ src = readl(&exynos_clock->src_fsys);
+ div = readl(&exynos_clock->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(&exynos_clock->div_top1)
+ >> bit_info->div_bit) & 0x7) + 1;
+ div = ((readl(&exynos_clock->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)
+{
+ unsigned long div;
+ unsigned long armclk;
+ unsigned int arm_ratio;
+ unsigned int arm2_ratio;
+
+ div = readl(&exynos_clock->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;
+}
+
+struct arm_clk_ratios *get_arm_clk_ratios(void)
+{
+ struct arm_clk_ratios *arm_ratio;
+ unsigned long arm_freq = 1700; /* FIXME: use get_arm_clk() */
+ int i;
+
+ 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;
+ }
+
+ return NULL;
+}
+
+/* exynos5: set the mmc clock */
+void set_mmc_clk(int dev_index, unsigned int div)
+{
+ 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 = &exynos_clock->div_fsys1;
+ } else {
+ addr = &exynos_clock->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)
+{
+ unsigned shift;
+ unsigned mask = 0xff;
+ u32 *reg;
+
+ /*
+ * For now we only handle a very small subset of peripherals 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 = &exynos_clock->div_peric1;
+ shift = 8;
+ break;
+ case PERIPH_ID_SPI1:
+ reg = &exynos_clock->div_peric1;
+ shift = 24;
+ break;
+ case PERIPH_ID_SPI2:
+ reg = &exynos_clock->div_peric2;
+ shift = 8;
+ break;
+ case PERIPH_ID_SPI3:
+ reg = &exynos_clock->sclk_div_isp;
+ shift = 4;
+ break;
+ case PERIPH_ID_SPI4:
+ reg = &exynos_clock->sclk_div_isp;
+ shift = 16;
+ break;
+ default:
+ printk(BIOS_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)
+{
+ unsigned shift;
+ unsigned mask = 0xff;
+ u32 *reg;
+
+ switch (periph_id) {
+ case PERIPH_ID_SPI0:
+ reg = &exynos_clock->div_peric1;
+ shift = 0;
+ break;
+ case PERIPH_ID_SPI1:
+ reg = &exynos_clock->div_peric1;
+ shift = 16;
+ break;
+ case PERIPH_ID_SPI2:
+ reg = &exynos_clock->div_peric2;
+ shift = 0;
+ break;
+ case PERIPH_ID_SPI3:
+ reg = &exynos_clock->sclk_div_isp;
+ shift = 0;
+ break;
+ case PERIPH_ID_SPI4:
+ reg = &exynos_clock->sclk_div_isp;
+ shift = 12;
+ break;
+ default:
+ printk(BIOS_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;
+
+ printk(BIOS_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;
+
+ printk(BIOS_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_scalar;
+ 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_scalar = clock_calc_best_scalar(4, 8, 400000000, rate, &fine);
+ if (main_scalar < 0) {
+ printk(BIOS_DEBUG, "%s: Cannot set clock rate for periph %d",
+ __func__, periph_id);
+ return -1;
+ }
+ clock_ll_set_ratio(periph_id, main_scalar - 1);
+ clock_ll_set_pre_ratio(periph_id, fine - 1);
+ break;
+ default:
+ printk(BIOS_DEBUG, "%s: Unsupported peripheral ID %d\n", __func__,
+ periph_id);
+ return -1;
+ }
+
+ return 0;
+}
+
+int clock_set_mshci(enum periph_id peripheral)
+{
+ 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 = &exynos_clock->div_fsys1;
+ break;
+ case PERIPH_ID_SDMMC2:
+ addr = &exynos_clock->div_fsys2;
+ break;
+ default:
+ printk(BIOS_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;
+}
+
+int clock_epll_set_rate(unsigned long rate)
+{
+ unsigned int epll_con, epll_con_k;
+ unsigned int i;
+ unsigned int lockcnt;
+ struct mono_time current, end;
+
+ epll_con = readl(&exynos_clock->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 generate 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, &exynos_clock->epll_lock);
+ writel(epll_con, &exynos_clock->epll_con0);
+ writel(epll_con_k, &exynos_clock->epll_con1);
+
+ timer_monotonic_get(¤t);
+ end = current;
+ mono_time_add_msecs(&end, TIMEOUT_EPLL_LOCK);
+
+ while (!(readl(&exynos_clock->epll_con0) &
+ (0x1 << EXYNOS5_EPLLCON0_LOCKED_SHIFT))) {
+ if (mono_time_after(¤t, &end)) {
+ printk(BIOS_DEBUG,
+ "%s: Timeout waiting for EPLL lock\n",
+ __func__);
+ return -1;
+ }
+ timer_monotonic_get(¤t);
+ }
+
+ return 0;
+}
+
+void clock_select_i2s_clk_source(void)
+{
+ clrsetbits_le32(&exynos_clock->src_peric1, AUDIO1_SEL_MASK,
+ (CLK_SRC_SCLK_EPLL));
+}
+
+int clock_set_i2s_clk_prescaler(unsigned int src_frq, unsigned int dst_frq)
+{
+ unsigned int div ;
+
+ if ((dst_frq == 0) || (src_frq == 0)) {
+ printk(BIOS_DEBUG, "%s: Invalid frequency input for prescaler\n", __func__);
+ printk(BIOS_DEBUG, "src frq = %d des frq = %d ", src_frq, dst_frq);
+ return -1;
+ }
+
+ div = (src_frq / dst_frq);
+ if (div > AUDIO_1_RATIO_MASK) {
+ printk(BIOS_DEBUG, "%s: Frequency ratio is out of range\n", __func__);
+ printk(BIOS_DEBUG, "src frq = %d des frq = %d ", src_frq, dst_frq);
+ return -1;
+ }
+ clrsetbits_le32(&exynos_clock->div_peric4, AUDIO_1_RATIO_MASK,
+ (div & AUDIO_1_RATIO_MASK));
+ return 0;
+}
diff --git a/src/soc/samsung/exynos5250/clock_init.c b/src/soc/samsung/exynos5250/clock_init.c
new file mode 100644
index 0000000..c8cf3ba
--- /dev/null
+++ b/src/soc/samsung/exynos5250/clock_init.c
@@ -0,0 +1,442 @@
+/*
+ * This file is part of the coreboot project.
+ *
+ * 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; 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
+ */
+
+/* Clock setup for SMDK5250 board based on EXYNOS5 */
+
+#include <delay.h>
+#include <console/console.h>
+#include "clk.h"
+#include "dp.h"
+#include "setup.h"
+
+void system_clock_init(struct mem_timings *mem,
+ struct arm_clk_ratios *arm_clk_ratio)
+{
+ u32 val, tmp;
+
+ /* Turn on the MCT as early as possible. */
+ exynos_mct->g_tcon |= (1 << 8);
+
+ clrbits_le32(&exynos_clock->src_cpu, MUX_APLL_SEL_MASK);
+ do {
+ val = readl(&exynos_clock->mux_stat_cpu);
+ } while ((val | MUX_APLL_SEL_MASK) != val);
+
+ clrbits_le32(&exynos_clock->src_core1, MUX_MPLL_SEL_MASK);
+ do {
+ val = readl(&exynos_clock->mux_stat_core1);
+ } while ((val | MUX_MPLL_SEL_MASK) != val);
+
+ clrbits_le32(&exynos_clock->src_top2, MUX_CPLL_SEL_MASK);
+ clrbits_le32(&exynos_clock->src_top2, MUX_EPLL_SEL_MASK);
+ clrbits_le32(&exynos_clock->src_top2, MUX_VPLL_SEL_MASK);
+ clrbits_le32(&exynos_clock->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(&exynos_clock->mux_stat_top2);
+ } while ((val | tmp) != val);
+
+ clrbits_le32(&exynos_clock->src_cdrex, MUX_BPLL_SEL_MASK);
+ do {
+ val = readl(&exynos_clock->mux_stat_cdrex);
+ } while ((val | MUX_BPLL_SEL_MASK) != val);
+
+ /* PLL locktime */
+ writel(APLL_LOCK_VAL, &exynos_clock->apll_lock);
+
+ writel(MPLL_LOCK_VAL, &exynos_clock->mpll_lock);
+
+ writel(BPLL_LOCK_VAL, &exynos_clock->bpll_lock);
+
+ writel(CPLL_LOCK_VAL, &exynos_clock->cpll_lock);
+
+ writel(GPLL_LOCK_VAL, &exynos_clock->gpll_lock);
+
+ writel(EPLL_LOCK_VAL, &exynos_clock->epll_lock);
+
+ writel(VPLL_LOCK_VAL, &exynos_clock->vpll_lock);
+
+ writel(CLK_REG_DISABLE, &exynos_clock->pll_div2_sel);
+
+ writel(MUX_HPM_SEL_MASK, &exynos_clock->src_cpu);
+ do {
+ val = readl(&exynos_clock->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, &exynos_clock->div_cpu0);
+ do {
+ val = readl(&exynos_clock->div_stat_cpu0);
+ } while (0 != val);
+
+ writel(CLK_DIV_CPU1_VAL, &exynos_clock->div_cpu1);
+ do {
+ val = readl(&exynos_clock->div_stat_cpu1);
+ } while (0 != val);
+
+ /* switch A15 clock source to OSC clock before changing APLL */
+ clrbits_le32(&exynos_clock->src_cpu, APLL_FOUT);
+
+ /* Set APLL */
+ writel(APLL_CON1_VAL, &exynos_clock->apll_con1);
+ val = set_pll(arm_clk_ratio->apll_mdiv, arm_clk_ratio->apll_pdiv,
+ arm_clk_ratio->apll_sdiv);
+ writel(val, &exynos_clock->apll_con0);
+ while ((readl(&exynos_clock->apll_con0) & APLL_CON0_LOCKED) == 0)
+ ;
+
+ /* now it is safe to switch to APLL */
+ setbits_le32(&exynos_clock->src_cpu, APLL_FOUT);
+
+ /* Set MPLL */
+ writel(MPLL_CON1_VAL, &exynos_clock->mpll_con1);
+ val = set_pll(mem->mpll_mdiv, mem->mpll_pdiv, mem->mpll_sdiv);
+ writel(val, &exynos_clock->mpll_con0);
+ while ((readl(&exynos_clock->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(&exynos_clock->pll_div2_sel, MUX_MPLL_FOUT_SEL);
+
+ /* Set BPLL */
+ if (mem->use_bpll) {
+ writel(BPLL_CON1_VAL, &exynos_clock->bpll_con1);
+ val = set_pll(mem->bpll_mdiv, mem->bpll_pdiv, mem->bpll_sdiv);
+ writel(val, &exynos_clock->bpll_con0);
+ while ((readl(&exynos_clock->bpll_con0) & BPLL_CON0_LOCKED) == 0)
+ ;
+
+ setbits_le32(&exynos_clock->pll_div2_sel, MUX_BPLL_FOUT_SEL);
+ }
+
+ /* Set CPLL */
+ writel(CPLL_CON1_VAL, &exynos_clock->cpll_con1);
+ val = set_pll(mem->cpll_mdiv, mem->cpll_pdiv, mem->cpll_sdiv);
+ writel(val, &exynos_clock->cpll_con0);
+ while ((readl(&exynos_clock->cpll_con0) & CPLL_CON0_LOCKED) == 0)
+ ;
+
+ /* Set GPLL */
+ writel(GPLL_CON1_VAL, &exynos_clock->gpll_con1);
+ val = set_pll(mem->gpll_mdiv, mem->gpll_pdiv, mem->gpll_sdiv);
+ writel(val, &exynos_clock->gpll_con0);
+ while ((readl(&exynos_clock->gpll_con0) & GPLL_CON0_LOCKED) == 0)
+ ;
+
+ /* Set EPLL */
+ writel(EPLL_CON2_VAL, &exynos_clock->epll_con2);
+ writel(EPLL_CON1_VAL, &exynos_clock->epll_con1);
+ val = set_pll(mem->epll_mdiv, mem->epll_pdiv, mem->epll_sdiv);
+ writel(val, &exynos_clock->epll_con0);
+ while ((readl(&exynos_clock->epll_con0) & EPLL_CON0_LOCKED) == 0)
+ ;
+
+ /* Set VPLL */
+ writel(VPLL_CON2_VAL, &exynos_clock->vpll_con2);
+ writel(VPLL_CON1_VAL, &exynos_clock->vpll_con1);
+ val = set_pll(mem->vpll_mdiv, mem->vpll_pdiv, mem->vpll_sdiv);
+ writel(val, &exynos_clock->vpll_con0);
+ while ((readl(&exynos_clock->vpll_con0) & VPLL_CON0_LOCKED) == 0)
+ ;
+
+ writel(CLK_SRC_CORE0_VAL, &exynos_clock->src_core0);
+ writel(CLK_DIV_CORE0_VAL, &exynos_clock->div_core0);
+ while (readl(&exynos_clock->div_stat_core0) != 0)
+ ;
+
+ writel(CLK_DIV_CORE1_VAL, &exynos_clock->div_core1);
+ while (readl(&exynos_clock->div_stat_core1) != 0)
+ ;
+
+ writel(CLK_DIV_SYSRGT_VAL, &exynos_clock->div_sysrgt);
+ while (readl(&exynos_clock->div_stat_sysrgt) != 0)
+ ;
+
+ writel(CLK_DIV_ACP_VAL, &exynos_clock->div_acp);
+ while (readl(&exynos_clock->div_stat_acp) != 0)
+ ;
+
+ writel(CLK_DIV_SYSLFT_VAL, &exynos_clock->div_syslft);
+ while (readl(&exynos_clock->div_stat_syslft) != 0)
+ ;
+
+ writel(CLK_SRC_TOP0_VAL, &exynos_clock->src_top0);
+ writel(CLK_SRC_TOP1_VAL, &exynos_clock->src_top1);
+ writel(TOP2_VAL, &exynos_clock->src_top2);
+ writel(CLK_SRC_TOP3_VAL, &exynos_clock->src_top3);
+
+ writel(CLK_DIV_TOP0_VAL, &exynos_clock->div_top0);
+ while (readl(&exynos_clock->div_stat_top0))
+ ;
+
+ writel(CLK_DIV_TOP1_VAL, &exynos_clock->div_top1);
+ while (readl(&exynos_clock->div_stat_top1))
+ ;
+
+ writel(CLK_SRC_LEX_VAL, &exynos_clock->src_lex);
+ while (1) {
+ val = readl(&exynos_clock->mux_stat_lex);
+ if (val == (val | 1))
+ break;
+ }
+
+ writel(CLK_DIV_LEX_VAL, &exynos_clock->div_lex);
+ while (readl(&exynos_clock->div_stat_lex))
+ ;
+
+ writel(CLK_DIV_R0X_VAL, &exynos_clock->div_r0x);
+ while (readl(&exynos_clock->div_stat_r0x))
+ ;
+
+ writel(CLK_DIV_R0X_VAL, &exynos_clock->div_r0x);
+ while (readl(&exynos_clock->div_stat_r0x))
+ ;
+
+ writel(CLK_DIV_R1X_VAL, &exynos_clock->div_r1x);
+ while (readl(&exynos_clock->div_stat_r1x))
+ ;
+
+ if (mem->use_bpll) {
+ writel(MUX_BPLL_SEL_MASK | MUX_MCLK_CDREX_SEL |
+ MUX_MCLK_DPHY_SEL, &exynos_clock->src_cdrex);
+ } else {
+ writel(CLK_REG_DISABLE, &exynos_clock->src_cdrex);
+ }
+
+ writel(CLK_DIV_CDREX_VAL, &exynos_clock->div_cdrex);
+ while (readl(&exynos_clock->div_stat_cdrex))
+ ;
+
+ val = readl(&exynos_clock->src_cpu);
+ val |= CLK_SRC_CPU_VAL;
+ writel(val, &exynos_clock->src_cpu);
+
+ val = readl(&exynos_clock->src_top2);
+ val |= CLK_SRC_TOP2_VAL;
+ writel(val, &exynos_clock->src_top2);
+
+ val = readl(&exynos_clock->src_core1);
+ val |= CLK_SRC_CORE1_VAL;
+ writel(val, &exynos_clock->src_core1);
+
+ writel(CLK_SRC_FSYS0_VAL, &exynos_clock->src_fsys);
+ writel(CLK_DIV_FSYS0_VAL, &exynos_clock->div_fsys0);
+ while (readl(&exynos_clock->div_stat_fsys0))
+ ;
+
+ writel(CLK_REG_DISABLE, &exynos_clock->clkout_cmu_cpu);
+ writel(CLK_REG_DISABLE, &exynos_clock->clkout_cmu_core);
+ writel(CLK_REG_DISABLE, &exynos_clock->clkout_cmu_acp);
+ writel(CLK_REG_DISABLE, &exynos_clock->clkout_cmu_top);
+ writel(CLK_REG_DISABLE, &exynos_clock->clkout_cmu_lex);
+ writel(CLK_REG_DISABLE, &exynos_clock->clkout_cmu_r0x);
+ writel(CLK_REG_DISABLE, &exynos_clock->clkout_cmu_r1x);
+ writel(CLK_REG_DISABLE, &exynos_clock->clkout_cmu_cdrex);
+
+ writel(CLK_SRC_PERIC0_VAL, &exynos_clock->src_peric0);
+ writel(CLK_DIV_PERIC0_VAL, &exynos_clock->div_peric0);
+
+ writel(CLK_SRC_PERIC1_VAL, &exynos_clock->src_peric1);
+ writel(CLK_DIV_PERIC1_VAL, &exynos_clock->div_peric1);
+ writel(CLK_DIV_PERIC2_VAL, &exynos_clock->div_peric2);
+ writel(SCLK_SRC_ISP_VAL, &exynos_clock->sclk_src_isp);
+ writel(SCLK_DIV_ISP_VAL, &exynos_clock->sclk_div_isp);
+ writel(CLK_DIV_ISP0_VAL, &exynos_clock->div_isp0);
+ writel(CLK_DIV_ISP1_VAL, &exynos_clock->div_isp1);
+ writel(CLK_DIV_ISP2_VAL, &exynos_clock->div_isp2);
+
+ /* FIMD1 SRC CLK SELECTION */
+ writel(CLK_SRC_DISP1_0_VAL, &exynos_clock->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, &exynos_clock->div_fsys2);
+}
+
+void clock_gate(void)
+{
+ /* CLK_GATE_IP_SYSRGT */
+ clrbits_le32(&exynos_clock->gate_ip_sysrgt, CLK_C2C_MASK);
+
+ /* CLK_GATE_IP_ACP */
+ clrbits_le32(&exynos_clock->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(&exynos_clock->gate_bus_syslft, CLK_EFCLK_MASK);
+
+ /* CLK_GATE_IP_ISP0 */
+ clrbits_le32(&exynos_clock->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(&exynos_clock->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(&exynos_clock->gate_sclk_isp, SCLK_MPWM_ISP_MASK);
+
+ /* CLK_GATE_IP_GSCL */
+ clrbits_le32(&exynos_clock->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(&exynos_clock->gate_ip_disp1, CLK_SMMUTVX_MASK |
+ CLK_ASYNCTVX_MASK |
+ CLK_HDMI_MASK |
+ CLK_MIXER_MASK |
+ CLK_DSIM1_MASK);
+
+ /* CLK_GATE_IP_MFC */
+ clrbits_le32(&exynos_clock->gate_ip_mfc, CLK_SMMUMFCR_MASK |
+ CLK_SMMUMFCL_MASK |
+ CLK_MFC_MASK);
+
+ /* CLK_GATE_IP_GEN */
+ clrbits_le32(&exynos_clock->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(&exynos_clock->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(&exynos_clock->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
+ * Note: Keep CHIPID_APBIF ungated to ensure reading the product ID
+ * register (PRO_ID) works correctly when the OS kernel determines
+ * which chip it is running on.
+ */
+ clrbits_le32(&exynos_clock->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_GATE_BLOCK */
+ clrbits_le32(&exynos_clock->gate_block, CLK_ACP_MASK);
+
+ /* CLK_GATE_IP_CDREX */
+ clrbits_le32(&exynos_clock->gate_ip_cdrex, CLK_DPHY0_MASK |
+ CLK_DPHY1_MASK |
+ CLK_TZASC_DRBXR_MASK);
+
+}
+
+void clock_init_dp_clock(void)
+{
+ /* DP clock enable */
+ setbits_le32(&exynos_clock->gate_ip_disp1, CLK_GATE_DP1_ALLOW);
+
+ /* We run DP at 267 Mhz */
+ setbits_le32(&exynos_clock->div_disp1_0, CLK_DIV_DISP1_0_FIMD1);
+}
diff --git a/src/soc/samsung/exynos5250/cpu.c b/src/soc/samsung/exynos5250/cpu.c
new file mode 100644
index 0000000..6b3ee8b
--- /dev/null
+++ b/src/soc/samsung/exynos5250/cpu.c
@@ -0,0 +1,167 @@
+/*
+ * This file is part of the coreboot project.
+ *
+ * Copyright 2013 Google Inc.
+ * 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; 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 <stdlib.h>
+#include <string.h>
+#include <stddef.h>
+#include <delay.h>
+#include <console/console.h>
+#include <device/device.h>
+#include <cbmem.h>
+#include <arch/cache.h>
+#include "fimd.h"
+#include "dp-core.h"
+#include "cpu.h"
+#include "clk.h"
+#include "chip.h"
+
+static unsigned int cpu_id;
+static unsigned int cpu_rev;
+
+static void set_cpu_id(void)
+{
+ cpu_id = readl((void *)EXYNOS5_PRO_ID);
+ cpu_id = (0xC000 | ((cpu_id & 0x00FFF000) >> 12));
+
+ /*
+ * 0xC200: EXYNOS4210 EVT0
+ * 0xC210: EXYNOS4210 EVT1
+ */
+ if (cpu_id == 0xC200) {
+ cpu_id |= 0x10;
+ cpu_rev = 0;
+ } else if (cpu_id == 0xC210) {
+ cpu_rev = 1;
+ }
+}
+
+/* we distinguish a display port device from a raw graphics device
+ * because there are dramatic differences in startup depending on
+ * graphics usage. To make startup fast and easier to understand and
+ * debug we explicitly name this common case. The alternate approach,
+ * involving lots of machine and callbacks, is hard to debug and
+ * verify.
+ */
+static void exynos_displayport_init(device_t dev, u32 lcdbase,
+ unsigned long fb_size)
+{
+ int ret;
+ struct soc_samsung_exynos5250_config *conf = dev->chip_info;
+ /* put these on the stack. If, at some point, we want to move
+ * this code to a pre-ram stage, it will be much easier.
+ */
+ struct exynos5_fimd_panel panel;
+ memset(&panel, 0, sizeof(panel));
+
+ panel.is_dp = 1; /* Display I/F is eDP */
+ /* while it is true that we did a memset to zero,
+ * we leave some 'set to zero' entries here to make
+ * it clear what's going on. Graphics is confusing.
+ */
+ panel.is_mipi = 0;
+ panel.fixvclk = 0;
+ panel.ivclk = 0;
+ panel.clkval_f = conf->clkval_f;
+ panel.upper_margin = conf->upper_margin;
+ panel.lower_margin = conf->lower_margin;
+ panel.vsync = conf->vsync;
+ panel.left_margin = conf->left_margin;
+ panel.right_margin = conf->right_margin;
+ panel.hsync = conf->hsync;
+ panel.xres = conf->xres;
+ panel.yres = conf->yres;
+
+ printk(BIOS_SPEW, "LCD framebuffer @%p\n", (void *)(lcdbase));
+ memset((void *)lcdbase, 0, fb_size); /* clear the framebuffer */
+
+ /*
+ * We need to clean and invalidate the framebuffer region and disable
+ * caching as well. We assume that our dcache <--> memory address
+ * space is identity-mapped in 1MB chunks, so align accordingly.
+ *
+ * Note: We may want to do something clever to ensure the framebuffer
+ * region is aligned such that we don't change dcache policy for other
+ * stuff inadvertently.
+ */
+ uint32_t lower = ALIGN_DOWN(lcdbase, MiB);
+ uint32_t upper = ALIGN_UP(lcdbase + fb_size, MiB);
+
+ dcache_clean_invalidate_by_mva(lower, upper - lower);
+ mmu_config_range(lower / MiB, (upper - lower) / MiB, DCACHE_OFF);
+
+ printk(BIOS_DEBUG, "Initializing Exynos LCD.\n");
+
+ ret = lcd_ctrl_init(fb_size, &panel, (void *)lcdbase);
+}
+
+static void cpu_enable(device_t dev)
+{
+ unsigned long fb_size = FB_SIZE_KB * KiB;
+ u32 lcdbase = get_fb_base_kb() * KiB;
+
+ ram_resource(dev, 0, RAM_BASE_KB, RAM_SIZE_KB - FB_SIZE_KB);
+ mmio_resource(dev, 1, lcdbase / KiB, CEIL_DIV(fb_size, KiB));
+
+ exynos_displayport_init(dev, lcdbase, fb_size);
+
+ set_cpu_id();
+}
+
+static void cpu_init(device_t dev)
+{
+ printk(BIOS_INFO, "CPU: S5P%X @ %ldMHz\n",
+ cpu_id, get_arm_clk() / (1024*1024));
+}
+
+static void cpu_noop(device_t dev)
+{
+}
+
+static struct device_operations cpu_ops = {
+ .read_resources = cpu_noop,
+ .set_resources = cpu_noop,
+ .enable_resources = cpu_enable,
+ .init = cpu_init,
+ .scan_bus = 0,
+};
+
+static void enable_exynos5250_dev(device_t dev)
+{
+ dev->ops = &cpu_ops;
+}
+
+struct chip_operations cpu_samsung_exynos5250_ops = {
+ CHIP_NAME("CPU Samsung Exynos 5250")
+ .enable_dev = enable_exynos5250_dev,
+};
+
+void exynos5250_config_l2_cache(void)
+{
+ uint32_t val;
+
+ /*
+ * Bit 9 - L2 tag RAM setup (1 cycle)
+ * Bits 8:6 - L2 tag RAM latency (3 cycles)
+ * Bit 5 - L2 data RAM setup (1 cycle)
+ * Bits 2:0 - L2 data RAM latency (3 cycles)
+ */
+ val = (1 << 9) | (0x2 << 6) | (1 << 5) | (0x2);
+ write_l2ctlr(val);
+}
diff --git a/src/soc/samsung/exynos5250/cpu.h b/src/soc/samsung/exynos5250/cpu.h
new file mode 100644
index 0000000..10f9ef4
--- /dev/null
+++ b/src/soc/samsung/exynos5250/cpu.h
@@ -0,0 +1,87 @@
+/*
+ * This file is part of the coreboot project.
+ *
+ * Copyright (C) 2010 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; 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
+ */
+
+#ifndef CPU_SAMSUNG_EXYNOS5250_CPU_H
+#define CPU_SAMSUNG_EXYNOS5250_CPU_H
+
+#include <arch/io.h>
+
+/* Base address registers */
+#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_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_DRD_XHCI_BASE 0x12000000
+#define EXYNOS5_USB_DRD_PHY_BASE 0x12100000
+#define EXYNOS5_USB_DRD_DWC3_BASE 0x1200C100
+#define EXYNOS5_USB_HOST_EHCI_BASE 0x12110000
+#define EXYNOS5_USB_HOST_PHY_BASE 0x12130000
+#define EXYNOS5_MMC_BASE 0x12200000
+#define EXYNOS5_MSHC_BASE 0x12240000
+#define EXYNOS5_SROMC_BASE 0x12250000
+#define EXYNOS5_UART0_BASE 0x12C00000
+#define EXYNOS5_UART1_BASE 0x12C10000
+#define EXYNOS5_UART2_BASE 0x12C20000
+#define EXYNOS5_UART3_BASE 0x12C30000
+#define EXYNOS5_I2C_BASE 0x12C60000
+#define EXYNOS5_SPI0_BASE 0x12D20000
+#define EXYNOS5_SPI1_BASE 0x12D30000
+#define EXYNOS5_I2S_BASE 0x12D60000
+#define EXYNOS5_UART_ISP_BASE 0x13190000
+#define EXYNOS5_SPI_ISP_BASE 0x131A0000
+#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_DP0_BASE 0x14510000
+#define EXYNOS5_DP1_BASE 0x145B0000
+
+/* Marker values stored at the bottom of IRAM stack by SPL */
+#define EXYNOS5_SPL_MARKER 0xb004f1a9 /* hexspeak word: bootflag */
+
+#define EXYNOS5_SPI_NUM_CONTROLLERS 5
+#define EXYNOS_I2C_MAX_CONTROLLERS 8
+
+void exynos5250_config_l2_cache(void);
+
+extern struct tmu_info exynos5250_tmu_info;
+
+/* TODO clean up defines. */
+#define FB_SIZE_KB 4096
+#define RAM_BASE_KB (CONFIG_SYS_SDRAM_BASE >> 10)
+#define RAM_SIZE_KB (CONFIG_DRAM_SIZE_MB << 10UL)
+
+static inline u32 get_fb_base_kb(void)
+{
+ return RAM_BASE_KB + RAM_SIZE_KB - FB_SIZE_KB;
+}
+
+#endif /* _EXYNOS5250_CPU_H */
diff --git a/src/soc/samsung/exynos5250/dmc.h b/src/soc/samsung/exynos5250/dmc.h
new file mode 100644
index 0000000..6388316
--- /dev/null
+++ b/src/soc/samsung/exynos5250/dmc.h
@@ -0,0 +1,353 @@
+/*
+ * 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
+ */
+
+#ifndef CPU_SAMSUNG_EXYNOS5250_DMC_H
+#define CPU_SAMSUNG_EXYNOS5250_DMC_H
+
+#ifndef __ASSEMBLER__
+
+#include "cpu.h"
+
+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;
+};
+
+static struct exynos5_dmc * const exynos_dmc = (void *)EXYNOS5_DMC_CTRL_BASE;
+
+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;
+};
+
+static struct exynos5_phy_control * const exynos_phy0_control =
+ (void *)EXYNOS5_DMC_PHY0_BASE;
+static struct exynos5_phy_control * const exynos_phy1_control =
+ (void *)EXYNOS5_DMC_PHY1_BASE;
+
+enum ddr_mode {
+ DDR_MODE_DDR2,
+ DDR_MODE_DDR3,
+ DDR_MODE_LPDDR2,
+ DDR_MODE_LPDDR3,
+
+ DDR_MODE_COUNT,
+};
+
+/* For reasons unknown, people are in the habit of taking a 32-bit
+ * field with 2 possible values and packing it with, say, 2 bits. A
+ * non-robust encoding, using only 2 bits of a 32-bit field, is
+ * incredibly difficult to deal with when things go wrong, because
+ * there are a lot of things that get expressed as 0, 1, or 2. If
+ * you're scanning with jtag or dumping memory it is really hard to
+ * tell when you've hit the beginning of the struct. So, let's be a
+ * bit smart here. First, while it's common to let the enum count
+ * entries for you, when there are two of them, we can do the
+ * counting. And, let's set the values to something we can easily scan
+ * for in memory. Since '1' and '2' are rather common, we pick
+ * something that's actually of some value when things go wrong. This
+ * setup motivated by a use case: something's going wrong and having a
+ * manuf name of '1' or '2' is completely useless!
+ */
+enum mem_manuf {
+ MEM_MANUF_AUTODETECT,
+ MEM_MANUF_ELPIDA = 0xe7b1da,
+ MEM_MANUF_SAMSUNG = 0x5a5096,
+
+ MEM_MANUF_COUNT = 2, // fancy that.
+};
+
+enum {
+ MEM_TIMINGS_MSR_COUNT = 4,
+};
+
+#define DMC_INTERLEAVE_SIZE 0x1f
+
+/* 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)
+
+/* These are the memory timings for a particular memory type and speed */
+struct mem_timings {
+ enum mem_manuf mem_manuf; /* Memory manufacturer */
+ enum ddr_mode mem_type; /* Memory type */
+ unsigned int frequency_mhz; /* Frequency of memory in MHz */
+
+ /* Here follow the timing parameters for the selected memory */
+ uint8_t apll_mdiv;
+ uint8_t apll_pdiv;
+ uint8_t apll_sdiv;
+ uint8_t mpll_mdiv;
+ uint8_t mpll_pdiv;
+ uint8_t mpll_sdiv;
+ uint8_t cpll_mdiv;
+ uint8_t cpll_pdiv;
+ uint8_t cpll_sdiv;
+ uint8_t gpll_pdiv;
+ uint16_t gpll_mdiv;
+ uint8_t gpll_sdiv;
+ uint8_t epll_mdiv;
+ uint8_t epll_pdiv;
+ uint8_t epll_sdiv;
+ uint8_t vpll_mdiv;
+ uint8_t vpll_pdiv;
+ uint8_t vpll_sdiv;
+ uint8_t bpll_mdiv;
+ uint8_t bpll_pdiv;
+ uint8_t bpll_sdiv;
+ uint8_t use_bpll; /* 1 to use BPLL for cdrex, 0 to use MPLL */
+ uint8_t pclk_cdrex_ratio;
+ unsigned int direct_cmd_msr[MEM_TIMINGS_MSR_COUNT];
+
+ unsigned int timing_ref;
+ unsigned int timing_row;
+ unsigned int timing_data;
+ unsigned int timing_power;
+
+ /* DQS, DQ, DEBUG offsets */
+ unsigned int phy0_dqs;
+ unsigned int phy1_dqs;
+ unsigned int phy0_dq;
+ unsigned int phy1_dq;
+ uint8_t phy0_tFS;
+ uint8_t phy1_tFS;
+ uint8_t phy0_pulld_dqs;
+ uint8_t phy1_pulld_dqs;
+
+ uint8_t lpddr3_ctrl_phy_reset;
+ uint8_t ctrl_start_point;
+ uint8_t ctrl_inc;
+ uint8_t ctrl_start;
+ uint8_t ctrl_dll_on;
+ uint8_t ctrl_ref;
+
+ uint8_t ctrl_force;
+ uint8_t ctrl_rdlat;
+ uint8_t ctrl_bstlen;
+
+ uint8_t fp_resync;
+ uint8_t iv_size;
+ uint8_t dfi_init_start;
+ uint8_t aref_en;
+
+ uint8_t rd_fetch;
+
+ uint8_t zq_mode_dds;
+ uint8_t zq_mode_term;
+ uint8_t zq_mode_noterm; /* 1 to allow termination disable */
+
+ unsigned int memcontrol;
+ unsigned int memconfig;
+
+ unsigned int membaseconfig0;
+ unsigned int membaseconfig1;
+ unsigned int prechconfig_tp_cnt;
+ unsigned int dpwrdn_cyc;
+ unsigned int dsref_cyc;
+ unsigned int concontrol;
+ /* Channel and Chip Selection */
+ uint8_t dmc_channels; /* number of memory channels */
+ uint8_t chips_per_channel; /* number of chips per channel */
+ uint8_t chips_to_configure; /* number of chips to configure */
+ uint8_t send_zq_init; /* 1 to send this command */
+ unsigned int impedance; /* drive strength impedance */
+ uint8_t gate_leveling_enable; /* check gate leveling is enabled */
+};
+
+/**
+ * Get the correct memory timings for our selected memory type and speed.
+ *
+ * @return pointer to the memory timings that we should use
+ */
+struct mem_timings *get_mem_timings(void);
+
+#endif
+#endif
diff --git a/src/soc/samsung/exynos5250/dmc_common.c b/src/soc/samsung/exynos5250/dmc_common.c
new file mode 100644
index 0000000..624097b
--- /dev/null
+++ b/src/soc/samsung/exynos5250/dmc_common.c
@@ -0,0 +1,182 @@
+/*
+ * This file is part of the coreboot project.
+ *
+ * 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; 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
+ */
+
+/* Mem setup common file for different types of DDR present on SMDK5250 boards.
+ */
+
+#include <console/console.h>
+#include <arch/io.h>
+#include <delay.h>
+#include "setup.h"
+#include "dmc.h"
+#include "clk.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 manually 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) {
+ udelay(1);
+ 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) {
+ udelay(1);
+ 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 Resynchronization */
+ val = readl(&dmc->phycontrol0);
+ val |= FP_RSYNC;
+ writel(val, &dmc->phycontrol0);
+
+ /* Reset Force DLL Resynchronization */
+ 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.
+ */
+ udelay(100);
+
+ /* Sending EMRS/MRS commands */
+ for (i = 0; i < MEM_TIMINGS_MSR_COUNT; i++) {
+ writel(mem->direct_cmd_msr[i] | mask,
+ &dmc->directcmd);
+ udelay(100);
+ }
+
+ if (mem->send_zq_init) {
+ /* Sending ZQINIT command */
+ writel(DIRECT_CMD_ZQINIT | mask,
+ &dmc->directcmd);
+ /*
+ * FIXME: This was originally sdelay(10000)
+ * in the imported u-boot code. That may have
+ * been meant to be sdelay(0x10000) since that
+ * was used elsewhere in this function. Either
+ * way seems to work, though.
+ */
+ udelay(12);
+ }
+ }
+ }
+}
+
+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);
+ udelay(100);
+ }
+ }
+}
+
+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);
+}
diff --git a/src/soc/samsung/exynos5250/dmc_init_ddr3.c b/src/soc/samsung/exynos5250/dmc_init_ddr3.c
new file mode 100644
index 0000000..89a7b613
--- /dev/null
+++ b/src/soc/samsung/exynos5250/dmc_init_ddr3.c
@@ -0,0 +1,250 @@
+/*
+ * This file is part of the coreboot project.
+ *
+ * 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; 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
+ */
+
+/* DDR3 mem setup file for SMDK5250 board based on EXYNOS5 */
+
+#include <delay.h>
+#include <arch/io.h>
+#include <console/console.h>
+#include "clk.h"
+#include "cpu.h"
+#include "dmc.h"
+#include "setup.h"
+
+#define RDLVL_COMPLETE_TIMEOUT 10000
+
+static void reset_phy_ctrl(void)
+{
+ writel(LPDDR3PHY_CTRL_PHY_RESET_ENABLE, &exynos_clock->lpddr3phy_ctrl);
+ writel(LPDDR3PHY_CTRL_PHY_RESET_DISABLE, &exynos_clock->lpddr3phy_ctrl);
+
+#if 0
+ /*
+ * 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);
+#endif
+ udelay(500);
+}
+
+int ddr3_mem_ctrl_init(struct mem_timings *mem, unsigned long mem_iv_size,
+ int mem_reset)
+{
+ unsigned int val;
+ int i;
+
+ if (mem_reset)
+ 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, &exynos_phy0_control->phy_con39);
+ writel(val, &exynos_phy1_control->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, &exynos_phy0_control->phy_con42);
+ writel(val, &exynos_phy1_control->phy_con42);
+
+ /* ZQ Calibration */
+ if (dmc_config_zq(mem, exynos_phy0_control, exynos_phy1_control)){
+ printk(BIOS_EMERG, "DRAM ZQ CALIBRATION FAILURE\n");
+ return SETUP_ERR_ZQ_CALIBRATION_FAILURE;
+ }
+
+ /* DQ Signal */
+ writel(mem->phy0_pulld_dqs, &exynos_phy0_control->phy_con14);
+ writel(mem->phy1_pulld_dqs, &exynos_phy1_control->phy_con14);
+
+ writel(mem->concontrol | (mem->rd_fetch << CONCONTROL_RD_FETCH_SHIFT)
+ | (mem->dfi_init_start << CONCONTROL_DFI_INIT_START_SHIFT),
+ &exynos_dmc->concontrol);
+
+ update_reset_dll(exynos_dmc, DDR_MODE_DDR3);
+
+ /* DQS Signal */
+ writel(mem->phy0_dqs, &exynos_phy0_control->phy_con4);
+ writel(mem->phy1_dqs, &exynos_phy1_control->phy_con4);
+
+ writel(mem->phy0_dq, &exynos_phy0_control->phy_con6);
+ writel(mem->phy1_dq, &exynos_phy1_control->phy_con6);
+
+ writel(mem->phy0_tFS, &exynos_phy0_control->phy_con10);
+ writel(mem->phy1_tFS, &exynos_phy1_control->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, &exynos_phy0_control->phy_con12);
+ writel(val, &exynos_phy1_control->phy_con12);
+
+ /* Start DLL locking */
+ writel(val | (mem->ctrl_start << PHY_CON12_CTRL_START_SHIFT),
+ &exynos_phy0_control->phy_con12);
+ writel(val | (mem->ctrl_start << PHY_CON12_CTRL_START_SHIFT),
+ &exynos_phy1_control->phy_con12);
+
+ update_reset_dll(exynos_dmc, DDR_MODE_DDR3);
+
+ writel(mem->concontrol | (mem->rd_fetch << CONCONTROL_RD_FETCH_SHIFT),
+ &exynos_dmc->concontrol);
+
+ /* Memory Channel Inteleaving Size */
+ writel(mem->iv_size, &exynos_dmc->ivcontrol);
+
+ /* Set DMC MEMCONTROL register */
+ val = mem->memcontrol & ~DMC_MEMCONTROL_DSREF_ENABLE;
+ writel(val, &exynos_dmc->memcontrol);
+
+ writel(mem->memconfig, &exynos_dmc->memconfig0);
+ writel(mem->memconfig, &exynos_dmc->memconfig1);
+ writel(mem->membaseconfig0, &exynos_dmc->membaseconfig0);
+ writel(mem->membaseconfig1, &exynos_dmc->membaseconfig1);
+
+ /* Precharge Configuration */
+ writel(mem->prechconfig_tp_cnt << PRECHCONFIG_TP_CNT_SHIFT,
+ &exynos_dmc->prechconfig);
+
+ /* Power Down mode Configuration */
+ writel(mem->dpwrdn_cyc << PWRDNCONFIG_DPWRDN_CYC_SHIFT |
+ mem->dsref_cyc << PWRDNCONFIG_DSREF_CYC_SHIFT,
+ &exynos_dmc->pwrdnconfig);
+
+ /* TimingRow, TimingData, TimingPower and Timingaref
+ * values as per Memory AC parameters
+ */
+ writel(mem->timing_ref, &exynos_dmc->timingref);
+ writel(mem->timing_row, &exynos_dmc->timingrow);
+ writel(mem->timing_data, &exynos_dmc->timingdata);
+ writel(mem->timing_power, &exynos_dmc->timingpower);
+
+ /* Send PALL command */
+ dmc_config_prech(mem, exynos_dmc);
+
+ if (mem_reset) {
+ /* Send NOP, MRS and ZQINIT commands.
+ * Sending MRS command will reset the DRAM. We should not be
+ * reseting the DRAM after resume, this will lead to memory
+ * corruption as DRAM content is lost after DRAM reset
+ */
+ dmc_config_mrs(mem, exynos_dmc);
+ }
+
+ if (mem->gate_leveling_enable) {
+ val = PHY_CON0_RESET_VAL;
+ val |= P0_CMD_EN;
+ writel(val, &exynos_phy0_control->phy_con0);
+ writel(val, &exynos_phy1_control->phy_con0);
+
+ val = PHY_CON2_RESET_VAL;
+ val |= INIT_DESKEW_EN;
+ writel(val, &exynos_phy0_control->phy_con2);
+ writel(val, &exynos_phy1_control->phy_con2);
+
+ val = PHY_CON0_RESET_VAL;
+ val |= P0_CMD_EN;
+ val |= BYTE_RDLVL_EN;
+ writel(val, &exynos_phy0_control->phy_con0);
+ writel(val, &exynos_phy1_control->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, &exynos_phy0_control->phy_con12);
+ writel(val, &exynos_phy1_control->phy_con12);
+
+ val = PHY_CON2_RESET_VAL;
+ val |= INIT_DESKEW_EN;
+ val |= RDLVL_GATE_EN;
+ writel(val, &exynos_phy0_control->phy_con2);
+ writel(val, &exynos_phy1_control->phy_con2);
+
+ val = PHY_CON0_RESET_VAL;
+ val |= P0_CMD_EN;
+ val |= BYTE_RDLVL_EN;
+ val |= CTRL_SHGATE;
+ writel(val, &exynos_phy0_control->phy_con0);
+ writel(val, &exynos_phy1_control->phy_con0);
+
+ val = PHY_CON1_RESET_VAL;
+ val &= ~(CTRL_GATEDURADJ_MASK);
+ writel(val, &exynos_phy0_control->phy_con1);
+ writel(val, &exynos_phy1_control->phy_con1);
+
+ writel(CTRL_RDLVL_GATE_ENABLE, &exynos_dmc->rdlvl_config);
+ i = RDLVL_COMPLETE_TIMEOUT;
+ while ((readl(&exynos_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
+ */
+ udelay(1);
+ i--;
+ }
+ if (!i){
+ printk(BIOS_EMERG, "Timeout on RDLVL. No DRAM.\n");
+ return SETUP_ERR_RDLV_COMPLETE_TIMEOUT;
+ }
+ writel(CTRL_RDLVL_GATE_DISABLE, &exynos_dmc->rdlvl_config);
+
+ writel(0, &exynos_phy0_control->phy_con14);
+ writel(0, &exynos_phy1_control->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, &exynos_phy0_control->phy_con12);
+ writel(val, &exynos_phy1_control->phy_con12);
+
+ update_reset_dll(exynos_dmc, DDR_MODE_DDR3);
+ }
+
+ /* Send PALL command */
+ dmc_config_prech(mem, exynos_dmc);
+
+ writel(mem->memcontrol, &exynos_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),
+ &exynos_dmc->concontrol);
+ return 0;
+}
diff --git a/src/soc/samsung/exynos5250/dp-core.h b/src/soc/samsung/exynos5250/dp-core.h
new file mode 100644
index 0000000..ab7e7e4
--- /dev/null
+++ b/src/soc/samsung/exynos5250/dp-core.h
@@ -0,0 +1,260 @@
+/*
+ * This file is part of the coreboot project.
+ *
+ * Copyright 2013 Google Inc.
+ * 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; 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
+ */
+
+/* Header file for Samsung DP (Display Port) interface driver. */
+
+#ifndef CPU_SAMSUNG_EXYNOS5250_DP_CORE_H
+#define CPU_SAMSUNG_EXYNOS5250_DP_CORE_H
+
+#define STREAM_ON_TIMEOUT 100
+#define PLL_LOCK_TIMEOUT 10
+#define DP_INIT_TRIES 10
+#define MAX_CR_LOOP 5
+#define MAX_EQ_LOOP 4
+
+/* Link rate type */
+enum link_rate {
+ LINK_RATE_1_62GBPS = 0x06,
+ LINK_RATE_2_70GBPS = 0x0a
+};
+
+/* Number of lanes supported */
+enum link_lane_count {
+ LANE_COUNT1 = 1,
+ LANE_COUNT2 = 2,
+ LANE_COUNT4 = 4
+};
+
+/* Pre emphasis level */
+enum pre_emphasis_level {
+ PRE_EMPHASIS_LEVEL_0,
+ PRE_EMPHASIS_LEVEL_1,
+ PRE_EMPHASIS_LEVEL_2,
+ PRE_EMPHASIS_LEVEL_3,
+};
+
+/* Type of color space */
+enum color_space {
+ COLOR_RGB,
+ COLOR_YCBCR422,
+ COLOR_YCBCR444
+};
+
+/* Video input Bit Per Color */
+enum color_depth {
+ COLOR_6,
+ COLOR_8,
+ COLOR_10,
+ COLOR_12
+};
+
+/* Type of YCbCr coefficient */
+enum color_coefficient {
+ COLOR_YCBCR601,
+ COLOR_YCBCR709
+};
+
+/* Color range */
+enum dynamic_range {
+ VESA,
+ CEA
+};
+
+/* Status of PLL clock */
+enum pll_status {
+ PLL_UNLOCKED,
+ PLL_LOCKED
+};
+
+/* To choose type of m_value */
+enum clock_recovery_m_value_type {
+ CALCULATED_M,
+ REGISTER_M
+};
+
+struct video_info {
+ enum color_space color_space;
+ enum dynamic_range dynamic_range;
+ enum color_coefficient ycbcr_coeff;
+ enum color_depth color_depth;
+
+ enum link_rate link_rate;
+ enum link_lane_count lane_count;
+
+ char *name;
+
+ unsigned int h_sync_polarity:1;
+ unsigned int v_sync_polarity:1;
+ unsigned int interlaced:1;
+};
+
+struct link_train {
+ u8 link_rate;
+ u8 lane_count;
+};
+
+struct s5p_dp_device {
+ unsigned int irq;
+ struct exynos5_dp *base;
+ struct video_info *video_info;
+ struct link_train link_train;
+};
+
+/* s5p_dp_reg.c */
+
+/*
+ * Reset DP module
+ *
+ * param dp pointer to main s5p-dp structure
+ */
+void s5p_dp_reset(struct s5p_dp_device *dp);
+/*
+ * Initialize DP to receive video stream
+ *
+ * param dp pointer to main s5p-dp structure
+ */
+void s5p_dp_init_video(struct s5p_dp_device *dp);
+/*
+ * Check whether PLL is locked
+ *
+ * param dp pointer to main s5p-dp structure
+ * return Lock status
+ */
+unsigned int s5p_dp_get_pll_lock_status(struct s5p_dp_device *dp);
+/*
+ * Initialize analog functions of DP
+ *
+ * param dp pointer to main s5p-dp structure
+ * return 0 on success
+ */
+int s5p_dp_init_analog_func(struct s5p_dp_device *dp);
+/*
+ * Initialize DP for AUX transaction
+ *
+ * param dp pointer to main s5p-dp structure
+ */
+void s5p_dp_init_aux(struct s5p_dp_device *dp);
+
+/*
+ * Start an AUX transaction.
+ *
+ * param dp pointer to main s5p-dp structure
+ */
+int s5p_dp_start_aux_transaction(struct s5p_dp_device *dp);
+
+/*
+ * Write a byte to DPCD register
+ *
+ * param dp pointer to main s5p-dp structure
+ * param reg_addr DPCD register to be written
+ * param data byte data to be written
+ * return write status
+ */
+int s5p_dp_write_byte_to_dpcd(struct s5p_dp_device *dp,
+ unsigned int reg_addr,
+ unsigned char data);
+/*
+ * Read a byte from DPCD register
+ *
+ * param dp pointer to main s5p-dp structure
+ * param reg_addr DPCD register to read
+ * param data read byte data
+ * return read status
+ */
+int s5p_dp_read_byte_from_dpcd(struct s5p_dp_device *dp,
+ unsigned int reg_addr,
+ unsigned char *data);
+/*
+ * Initialize DP video functions
+ *
+ * param dp pointer to main s5p-dp structure
+ */
+//void s5p_dp_init_video(struct s5p_dp_device *dp);
+
+/*
+ * Set color parameters for display
+ *
+ * param dp pointer to main s5p-dp structure
+ * param color_depth Video input Bit Per Color
+ * param color_space Colorimetric format of input video
+ * param dynamic_range VESA range or CEA range
+ * param coeff YCbCr Coefficients of input video
+ */
+void s5p_dp_set_video_color_format(struct s5p_dp_device *dp,
+ unsigned int color_depth,
+ unsigned int color_space,
+ unsigned int dynamic_range,
+ unsigned int coeff);
+/*
+ * Check whether video clock is on
+ *
+ * param dp pointer to main s5p-dp structure
+ * return clock status
+ */
+int s5p_dp_is_slave_video_stream_clock_on(struct s5p_dp_device *dp);
+/*
+ * Check whether video clock is on
+ *
+ * param dp pointer to main s5p-dp structure
+ * param type clock_recovery_m_value_type
+ * param m_value to calculate m_vid value
+ * param n_value to calculate n_vid value
+ */
+void s5p_dp_set_video_cr_mn(struct s5p_dp_device *dp,
+ enum clock_recovery_m_value_type type,
+ unsigned int m_value,
+ unsigned int n_value);
+/*
+ * Set DP to video slave mode thereby enabling video master
+ *
+ * param dp pointer to main s5p-dp structure
+ */
+void s5p_dp_enable_video_master(struct s5p_dp_device *dp);
+/*
+ * Check whether video stream is on
+ *
+ * param dp pointer to main s5p-dp structure
+ * return video stream status
+ */
+int s5p_dp_is_video_stream_on(struct s5p_dp_device *dp);
+/*
+ * Configure DP in slave mode
+ *
+ * param dp pointer to main s5p-dp structure
+ * param video_info pointer to main video_info structure.
+ */
+void s5p_dp_config_video_slave_mode(struct s5p_dp_device *dp,
+ struct video_info *video_info);
+
+/*
+ * Wait unitl HW link training done
+ *
+ * param dp pointer to main s5p-dp structure
+ */
+void s5p_dp_wait_hw_link_training_done(struct s5p_dp_device *dp);
+
+/* startup and init */
+struct exynos5_fimd_panel;
+void fb_init(unsigned long int fb_size, void *lcdbase,
+ struct exynos5_fimd_panel *pd);
+int dp_controller_init(struct s5p_dp_device *dp_device);
+int lcd_ctrl_init(unsigned long int fb_size,
+ struct exynos5_fimd_panel *panel_data, void *lcdbase);
+#endif /* CPU_SAMSUNG_EXYNOS5250_DP_CORE_H */
diff --git a/src/soc/samsung/exynos5250/dp-reg.c b/src/soc/samsung/exynos5250/dp-reg.c
new file mode 100644
index 0000000..1cc7088
--- /dev/null
+++ b/src/soc/samsung/exynos5250/dp-reg.c
@@ -0,0 +1,503 @@
+/*
+ * This file is part of the coreboot project.
+ *
+ * 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; 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
+ */
+
+/* Samsung DP (Display port) register interface driver. */
+
+#include <console/console.h>
+#include <arch/io.h>
+#include <delay.h>
+#include "timer.h"
+#include "clk.h"
+#include "cpu.h"
+#include "periph.h"
+#include "dp.h"
+#include "fimd.h"
+#include "dp-core.h"
+
+void s5p_dp_reset(struct s5p_dp_device *dp)
+{
+ u32 reg;
+ struct exynos5_dp *base = dp->base;
+
+ writel(RESET_DP_TX, &base->dp_tx_sw_reset);
+
+ /* Stop Video */
+ clrbits_le32(&base->video_ctl_1, VIDEO_EN);
+ clrbits_le32(&base->video_ctl_1, HDCP_VIDEO_MUTE);
+
+ reg = MASTER_VID_FUNC_EN_N | SLAVE_VID_FUNC_EN_N |
+ AUD_FIFO_FUNC_EN_N | AUD_FUNC_EN_N |
+ HDCP_FUNC_EN_N | SW_FUNC_EN_N;
+ writel(reg, &base->func_en_1);
+
+ reg = SSC_FUNC_EN_N | AUX_FUNC_EN_N |
+ SERDES_FIFO_FUNC_EN_N |
+ LS_CLK_DOMAIN_FUNC_EN_N;
+ writel(reg, &base->func_en_2);
+
+ udelay(20);
+
+ reg = LANE3_MAP_LOGIC_LANE_3 | LANE2_MAP_LOGIC_LANE_2 |
+ LANE1_MAP_LOGIC_LANE_1 | LANE0_MAP_LOGIC_LANE_0;
+
+ writel(reg, &base->lane_map);
+
+ writel(0x0, &base->sys_ctl_1);
+ writel(0x40, &base->sys_ctl_2);
+ writel(0x0, &base->sys_ctl_3);
+ writel(0x0, &base->sys_ctl_4);
+
+ writel(0x0, &base->pkt_send_ctl);
+ writel(0x0, &base->dp_hdcp_ctl);
+
+ writel(0x5e, &base->dp_hpd_deglitch_l);
+ writel(0x1a, &base->dp_hpd_deglitch_h);
+
+ writel(0x10, &base->dp_debug_ctl);
+
+ writel(0x0, &base->dp_phy_test);
+
+ writel(0x0, &base->dp_video_fifo_thrd);
+ writel(0x20, &base->dp_audio_margin);
+
+ writel(0x4, &base->m_vid_gen_filter_th);
+ writel(0x2, &base->m_aud_gen_filter_th);
+
+ writel(0x00000101, &base->soc_general_ctl);
+
+ /* Set Analog Parameters */
+ writel(0x10, &base->analog_ctl_1);
+ writel(0x0C, &base->analog_ctl_2);
+ writel(0x85, &base->analog_ctl_3);
+ writel(0x66, &base->pll_filter_ctl_1);
+ writel(0x0, &base->tx_amp_tuning_ctl);
+
+ /* Set interrupt pin assertion polarity as high */
+ writel(INT_POL0 | INT_POL1, &base->int_ctl);
+
+ /* Clear pending registers */
+ writel(0xff, &base->common_int_sta_1);
+ writel(0x4f, &base->common_int_sta_2);
+ writel(0xe0, &base->common_int_sta_3);
+ writel(0xe7, &base->common_int_sta_4);
+ writel(0x63, &base->dp_int_sta);
+
+ /* 0:mask,1: unmask */
+ writel(0x00, &base->common_int_mask_1);
+ writel(0x00, &base->common_int_mask_2);
+ writel(0x00, &base->common_int_mask_3);
+ writel(0x00, &base->common_int_mask_4);
+ writel(0x00, &base->int_sta_mask);
+}
+
+unsigned int s5p_dp_get_pll_lock_status(struct s5p_dp_device *dp)
+{
+ u32 reg;
+
+ reg = readl(&dp->base->dp_debug_ctl);
+ if (reg & PLL_LOCK)
+ return PLL_LOCKED;
+ else
+ return PLL_UNLOCKED;
+}
+
+int s5p_dp_init_analog_func(struct s5p_dp_device *dp)
+{
+ u32 reg;
+ struct mono_time current, end;
+ struct exynos5_dp *base = dp->base;
+
+ writel(0x00, &base->dp_phy_pd);
+
+ reg = PLL_LOCK_CHG;
+ writel(reg, &base->common_int_sta_1);
+
+ clrbits_le32(&base->dp_debug_ctl, (F_PLL_LOCK | PLL_LOCK_CTRL));
+
+ /* Power up PLL */
+ if (s5p_dp_get_pll_lock_status(dp) == PLL_UNLOCKED) {
+
+ clrbits_le32(&base->dp_pll_ctl, DP_PLL_PD);
+
+ timer_monotonic_get(¤t);
+ end = current;
+ mono_time_add_msecs(&end, PLL_LOCK_TIMEOUT);
+
+ while (s5p_dp_get_pll_lock_status(dp) == PLL_UNLOCKED) {
+ if (mono_time_after(¤t, &end)) {
+ printk(BIOS_ERR, "%s: PLL is not locked\n",
+ __func__);
+ return -1;
+ }
+ timer_monotonic_get(¤t);
+ }
+ }
+
+ /* Enable Serdes FIFO function and Link symbol clock domain module */
+ clrbits_le32(&base->func_en_2, (SERDES_FIFO_FUNC_EN_N |
+ LS_CLK_DOMAIN_FUNC_EN_N | AUX_FUNC_EN_N));
+ return 0;
+}
+
+void s5p_dp_init_aux(struct s5p_dp_device *dp)
+{
+ u32 reg;
+ struct exynos5_dp *base = dp->base;
+
+ /* Clear interrupts related to AUX channel */
+ reg = RPLY_RECEIV | AUX_ERR;
+ writel(reg, &base->dp_int_sta);
+
+ /* Disable AUX channel module */
+ setbits_le32(&base->func_en_2, AUX_FUNC_EN_N);
+
+ /* Disable AUX transaction H/W retry */
+ reg = (3 & AUX_BIT_PERIOD_MASK) << AUX_BIT_PERIOD_SHIFT;
+ reg |= (0 & AUX_HW_RETRY_COUNT_MASK) << AUX_HW_RETRY_COUNT_SHIFT;
+ reg |= (AUX_HW_RETRY_INTERVAL_600_US << AUX_HW_RETRY_INTERVAL_SHIFT);
+ writel(reg, &base->aux_hw_retry_ctl) ;
+
+ /* Receive AUX Channel DEFER commands equal to DEFFER_COUNT*64 */
+ reg = DEFER_CTRL_EN;
+ reg |= (1 & DEFER_COUNT_MASK) << DEFER_COUNT_SHIFT;
+ writel(reg, &base->aux_ch_defer_dtl);
+
+ /* Enable AUX channel module */
+ clrbits_le32(&base->func_en_2, AUX_FUNC_EN_N);
+}
+
+int s5p_dp_start_aux_transaction(struct s5p_dp_device *dp)
+{
+ int reg;
+ struct exynos5_dp *base = dp->base;
+
+ /* Enable AUX CH operation */
+ setbits_le32(&base->aux_ch_ctl_2, AUX_EN);
+
+ /* Is AUX CH command reply received? */
+ reg = readl(&base->dp_int_sta);
+ while (!(reg & RPLY_RECEIV))
+ reg = readl(&base->dp_int_sta);
+
+ /* Clear interrupt source for AUX CH command reply */
+ writel(RPLY_RECEIV, &base->dp_int_sta);
+
+ /* Clear interrupt source for AUX CH access error */
+ reg = readl(&base->dp_int_sta);
+ if (reg & AUX_ERR) {
+ printk(BIOS_ERR, "%s: AUX_ERR encountered, dp_int_sta: "
+ "0x%02x\n", __func__, reg);
+ writel(AUX_ERR, &base->dp_int_sta);
+ return -1;
+ }
+
+ /* Check AUX CH error access status */
+ reg = readl(&base->dp_int_sta);
+ if ((reg & AUX_STATUS_MASK) != 0) {
+ printk(BIOS_ERR, "AUX CH error happens: %d\n\n",
+ reg & AUX_STATUS_MASK);
+ return -1;
+ }
+
+ return 0;
+}
+
+int s5p_dp_write_byte_to_dpcd(struct s5p_dp_device *dp,
+ unsigned int reg_addr,
+ unsigned char data)
+{
+ u32 reg;
+ int i;
+ int retval;
+ struct exynos5_dp *base = dp->base;
+
+ for (i = 0; i < MAX_AUX_RETRY_COUNT; i++) {
+ /* Clear AUX CH data buffer */
+ writel(BUF_CLR, &base->buf_data_ctl);
+
+ /* Select DPCD device address */
+ reg = reg_addr >> AUX_ADDR_7_0_SHIFT;
+ reg &= AUX_ADDR_7_0_MASK;
+ writel(reg, &base->aux_addr_7_0);
+ reg = reg_addr >> AUX_ADDR_15_8_SHIFT;
+ reg &= AUX_ADDR_15_8_MASK;
+ writel(reg, &base->aux_addr_15_8);
+ reg = reg_addr >> AUX_ADDR_19_16_SHIFT;
+ reg &= AUX_ADDR_19_16_MASK;
+ writel(reg, &base->aux_addr_19_16);
+
+ /* Write data buffer */
+ reg = (unsigned int)data;
+ writel(reg, &base->buf_data_0);
+
+ /*
+ * Set DisplayPort transaction and write 1 byte
+ * If bit 3 is 1, DisplayPort transaction.
+ * If Bit 3 is 0, I2C transaction.
+ */
+ reg = AUX_TX_COMM_DP_TRANSACTION | AUX_TX_COMM_WRITE;
+ writel(reg, &base->aux_ch_ctl_1);
+
+ /* Start AUX transaction */
+ retval = s5p_dp_start_aux_transaction(dp);
+ if (retval == 0)
+ break;
+ else
+ printk(BIOS_DEBUG, "Aux Transaction fail!\n");
+ }
+
+ return retval;
+}
+
+int s5p_dp_read_byte_from_dpcd(struct s5p_dp_device *dp,
+ unsigned int reg_addr,
+ unsigned char *data)
+{
+ u32 reg;
+ int i;
+ int retval;
+ struct exynos5_dp *base = dp->base;
+
+ for (i = 0; i < MAX_AUX_RETRY_COUNT; i++) {
+ /* Clear AUX CH data buffer */
+ writel(BUF_CLR, &base->buf_data_ctl);
+
+ /* Select DPCD device address */
+ reg = reg_addr >> AUX_ADDR_7_0_SHIFT;
+ reg &= AUX_ADDR_7_0_MASK;
+ writel(reg, &base->aux_addr_7_0);
+ reg = reg_addr >> AUX_ADDR_15_8_SHIFT;
+ reg &= AUX_ADDR_15_8_MASK;
+ writel(reg, &base->aux_addr_15_8);
+ reg = reg_addr >> AUX_ADDR_19_16_SHIFT;
+ reg &= AUX_ADDR_19_16_MASK;
+ writel(reg, &base->aux_addr_19_16);
+
+ /*
+ * Set DisplayPort transaction and read 1 byte
+ * If bit 3 is 1, DisplayPort transaction.
+ * If Bit 3 is 0, I2C transaction.
+ */
+ reg = AUX_TX_COMM_DP_TRANSACTION | AUX_TX_COMM_READ;
+ writel(reg, &base->aux_ch_ctl_1);
+
+ /* Start AUX transaction */
+ retval = s5p_dp_start_aux_transaction(dp);
+ if (retval == 0)
+ break;
+ else
+ printk(BIOS_DEBUG, "Aux Transaction fail!\n");
+ }
+
+ /* Read data buffer */
+ if (!retval) {
+ reg = readl(&base->buf_data_0);
+ *data = (unsigned char)(reg & 0xff);
+ }
+
+ return retval;
+}
+
+void s5p_dp_init_video(struct s5p_dp_device *dp)
+{
+ u32 reg;
+ struct exynos5_dp *base = dp->base;
+
+ reg = VSYNC_DET | VID_FORMAT_CHG | VID_CLK_CHG;
+ writel(reg, &base->common_int_sta_1);
+
+ reg = 0x0;
+ writel(reg, &base->sys_ctl_1);
+
+ reg = (4 & CHA_CRI_MASK) << CHA_CRI_SHIFT;
+ reg |= CHA_CTRL;
+ writel(reg, &base->sys_ctl_2);
+
+ reg = 0x0;
+ writel(reg, &base->sys_ctl_3);
+}
+
+void s5p_dp_set_video_color_format(struct s5p_dp_device *dp,
+ unsigned int color_depth,
+ unsigned int color_space,
+ unsigned int dynamic_range,
+ unsigned int coeff)
+{
+ u32 reg;
+ struct exynos5_dp *base = dp->base;
+
+ /* Configure the input color depth, color space, dynamic range */
+ reg = (dynamic_range << IN_D_RANGE_SHIFT) |
+ (color_depth << IN_BPC_SHIFT) |
+ (color_space << IN_COLOR_F_SHIFT);
+ writel(reg, &base->video_ctl_2);
+
+ /* Set Input Color YCbCr Coefficients to ITU601 or ITU709 */
+ reg = readl(&base->video_ctl_3);
+ reg &= ~IN_YC_COEFFI_MASK;
+ if (coeff)
+ reg |= IN_YC_COEFFI_ITU709;
+ else
+ reg |= IN_YC_COEFFI_ITU601;
+ writel(reg, &base->video_ctl_3);
+}
+
+int s5p_dp_is_slave_video_stream_clock_on(struct s5p_dp_device *dp)
+{
+ u32 reg;
+ struct exynos5_dp *base = dp->base;
+
+ reg = readl(&base->sys_ctl_1);
+ writel(reg, &base->sys_ctl_1);
+
+ reg = readl(&base->sys_ctl_1);
+
+ if (!(reg & DET_STA))
+ return -1;
+
+ reg = readl(&base->sys_ctl_2);
+ writel(reg, &base->sys_ctl_2);
+
+ reg = readl(&base->sys_ctl_2);
+
+ if (reg & CHA_STA) {
+ printk(BIOS_DEBUG, "Input stream clk is changing\n");
+ return -1;
+ }
+
+ return 0;
+}
+
+void s5p_dp_set_video_cr_mn(struct s5p_dp_device *dp,
+ enum clock_recovery_m_value_type type,
+ unsigned int m_value,
+ unsigned int n_value)
+{
+ u32 reg;
+ struct exynos5_dp *base = dp->base;
+
+ if (type == REGISTER_M) {
+ setbits_le32(&base->sys_ctl_4, FIX_M_VID);
+
+ reg = m_value >> M_VID_0_VALUE_SHIFT;
+ writel(reg, &base->m_vid_0);
+
+ reg = (m_value >> M_VID_1_VALUE_SHIFT);
+ writel(reg, &base->m_vid_1);
+
+ reg = (m_value >> M_VID_2_VALUE_SHIFT);
+ writel(reg, &base->m_vid_2);
+
+ reg = n_value >> N_VID_0_VALUE_SHIFT;
+ writel(reg, &base->n_vid_0);
+
+ reg = (n_value >> N_VID_1_VALUE_SHIFT);
+ writel(reg, &base->n_vid_1);
+
+ reg = (n_value >> N_VID_2_VALUE_SHIFT);
+ writel(reg, &base->n_vid_2);
+ } else {
+ clrbits_le32(&base->sys_ctl_4, FIX_M_VID);
+
+ writel(0x00, &base->n_vid_0);
+ writel(0x80, &base->n_vid_1);
+ writel(0x00, &base->n_vid_2);
+ }
+}
+
+void s5p_dp_enable_video_master(struct s5p_dp_device *dp)
+{
+ u32 reg;
+ struct exynos5_dp *base = dp->base;
+
+ reg = readl(&base->soc_general_ctl);
+ reg &= ~VIDEO_MODE_MASK;
+ reg |= VIDEO_MODE_SLAVE_MODE;
+ writel(reg, &base->soc_general_ctl);
+}
+
+int s5p_dp_is_video_stream_on(struct s5p_dp_device *dp)
+{
+ u32 reg, i = 0;
+ struct mono_time current, end;
+ struct exynos5_dp *base = dp->base;
+
+ /* Wait for 4 VSYNC_DET interrupts */
+ timer_monotonic_get(¤t);
+ end = current;
+ mono_time_add_msecs(&end, STREAM_ON_TIMEOUT);
+
+ do {
+ reg = readl(&base->common_int_sta_1);
+ if (reg & VSYNC_DET) {
+ i++;
+ writel(reg | VSYNC_DET, &base->common_int_sta_1);
+ }
+ if (i == 4)
+ break;
+ timer_monotonic_get(¤t);
+ } while (mono_time_before(¤t, &end));
+
+ if (i != 4) {
+ printk(BIOS_DEBUG, "s5p_dp_is_video_stream_on timeout\n");
+ return -1;
+ }
+
+ return 0;
+}
+
+void s5p_dp_config_video_slave_mode(struct s5p_dp_device *dp,
+ struct video_info *video_info)
+{
+ u32 reg;
+ struct exynos5_dp *base = dp->base;
+
+ reg = readl(&base->func_en_1);
+ reg &= ~(MASTER_VID_FUNC_EN_N|SLAVE_VID_FUNC_EN_N);
+ reg |= MASTER_VID_FUNC_EN_N;
+ writel(reg, &base->func_en_1);
+
+ reg = readl(&base->video_ctl_10);
+ reg &= ~INTERACE_SCAN_CFG;
+ reg |= (video_info->interlaced << 2);
+ writel(reg, &base->video_ctl_10);
+
+ reg = readl(&base->video_ctl_10);
+ reg &= ~VSYNC_POLARITY_CFG;
+ reg |= (video_info->v_sync_polarity << 1);
+ writel(reg, &base->video_ctl_10);
+
+ reg = readl(&base->video_ctl_10);
+ reg &= ~HSYNC_POLARITY_CFG;
+ reg |= (video_info->h_sync_polarity << 0);
+ writel(reg, &base->video_ctl_10);
+
+ reg = AUDIO_MODE_SPDIF_MODE | VIDEO_MODE_SLAVE_MODE;
+ writel(reg, &base->soc_general_ctl);
+}
+
+void s5p_dp_wait_hw_link_training_done(struct s5p_dp_device *dp)
+{
+ u32 reg;
+ struct exynos5_dp *base = dp->base;
+
+ reg = readl(&base->dp_hw_link_training);
+ while (reg & HW_TRAINING_EN)
+ reg = readl(&base->dp_hw_link_training);
+}
diff --git a/src/soc/samsung/exynos5250/dp.h b/src/soc/samsung/exynos5250/dp.h
new file mode 100644
index 0000000..b1533c7
--- /dev/null
+++ b/src/soc/samsung/exynos5250/dp.h
@@ -0,0 +1,501 @@
+/*
+ * This file is part of the coreboot project.
+ *
+ * Copyright 2013 Google Inc.
+ * 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; 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
+ */
+
+/* Register map for Exynos5 DP */
+
+#ifndef CPU_SAMSUNG_EXYNOS5250_DP_H
+#define CPU_SAMSUNG_EXYNOS5250_DP_H
+
+/* DSIM register map */
+struct exynos5_dp {
+ u8 res1[0x10];
+ u32 dp_tx_version;
+ u32 dp_tx_sw_reset;
+ u32 func_en_1;
+ u32 func_en_2;
+ u32 video_ctl_1;
+ u32 video_ctl_2;
+ u32 video_ctl_3;
+ u32 video_ctl_4;
+ u32 clr_blue_cb;
+ u32 clr_green_y;
+ u32 clr_red_cr;
+ u32 video_ctl_8;
+ u8 res2[0x4];
+ u32 video_ctl_10;
+ u32 total_line_l;
+ u32 total_line_h;
+ u32 active_line_l;
+ u32 active_line_h;
+ u32 v_f_porch;
+ u32 vsync;
+ u32 v_b_porch;
+ u32 total_pixel_l;
+ u32 total_pixel_h;
+ u32 active_pixel_l;
+ u32 active_pixel_h;
+ u32 h_f_porch_l;
+ u32 h_f_porch_h;
+ u32 hsync_l;
+ u32 hysnc_h;
+ u32 h_b_porch_l;
+ u32 h_b_porch_h;
+ u32 vid_status;
+ u32 total_line_sta_l;
+ u32 total_line_sta_h;
+ u32 active_line_sta_l;
+ u32 active_line_sta_h;
+ u32 v_f_porch_sta;
+ u32 vsync_sta;
+ u32 v_b_porch_sta;
+ u32 total_pixel_sta_l;
+ u32 total_pixel_sta_h;
+ u32 active_pixel_sta_l;
+ u32 active_pixel_sta_h;
+ u32 h_f_porch_sta_l;
+ u32 h_f_porch_sta_h;
+ u32 hsync_sta_l;
+ u32 hsync_sta_h;
+ u32 h_b_porch_sta_l;
+ u32 h_b_porch__sta_h;
+ u8 res3[0x288];
+ u32 lane_map;
+ u8 res4[0x10];
+ u32 analog_ctl_1;
+ u32 analog_ctl_2;
+ u32 analog_ctl_3;
+ u32 pll_filter_ctl_1;
+ u32 tx_amp_tuning_ctl;
+ u8 res5[0xc];
+ u32 aux_hw_retry_ctl;
+ u8 res6[0x2c];
+ u32 int_state;
+ u32 common_int_sta_1;
+ u32 common_int_sta_2;
+ u32 common_int_sta_3;
+ u32 common_int_sta_4;
+ u8 res7[0x8];
+ u32 dp_int_sta;
+ u32 common_int_mask_1;
+ u32 common_int_mask_2;
+ u32 common_int_mask_3;
+ u32 common_int_mask_4;
+ u8 res8[0x08];
+ u32 int_sta_mask;
+ u32 int_ctl;
+ u8 res9[0x200];
+ u32 sys_ctl_1;
+ u32 sys_ctl_2;
+ u32 sys_ctl_3;
+ u32 sys_ctl_4;
+ u32 dp_vid_ctl;
+ u8 res10[0x2c];
+ u32 pkt_send_ctl;
+ u8 res11[0x4];
+ u32 dp_hdcp_ctl;
+ u8 res12[0x34];
+ u32 link_bw_set;
+ u32 lane_count_set;
+ u32 dp_training_ptn_set;
+ u32 ln0_link_trn_ctl;
+ u32 ln1_link_trn_ctl;
+ u32 ln2_link_trn_ctl;
+ u32 ln3_link_trn_ctl;
+ u32 dp_dn_spread;
+ u32 dp_hw_link_training;
+ u8 res13[0x1c];
+ u32 dp_debug_ctl;
+ u32 dp_hpd_deglitch_l;
+ u32 dp_hpd_deglitch_h;
+ u8 res14[0x14];
+ u32 dp_link_debug_ctl;
+ u8 res15[0x1c];
+ u32 m_vid_0;
+ u32 m_vid_1;
+ u32 m_vid_2;
+ u32 n_vid_0;
+ u32 n_vid_1;
+ u32 n_vid_2;
+ u32 m_vid_mon;
+ u32 dp_pll_ctl;
+ u32 dp_phy_pd;
+ u32 dp_phy_test;
+ u8 res16[0x8];
+ u32 dp_video_fifo_thrd;
+ u8 res17[0x8];
+ u32 dp_audio_margin;
+ u32 dp_dn_spread_ctl_1;
+ u32 dp_dn_spread_ctl_2;
+ u8 res18[0x18];
+ u32 dp_m_cal_ctl;
+ u32 m_vid_gen_filter_th;
+ u8 res19[0x14];
+ u32 m_aud_gen_filter_th;
+ u32 aux_ch_sta;
+ u32 aux_err_num;
+ u32 aux_ch_defer_dtl;
+ u32 aux_rx_comm;
+ u32 buf_data_ctl;
+ u32 aux_ch_ctl_1;
+ u32 aux_addr_7_0;
+ u32 aux_addr_15_8;
+ u32 aux_addr_19_16;
+ u32 aux_ch_ctl_2;
+ u8 res20[0x18];
+ u32 buf_data_0;
+ u8 res21[0x3c];
+ u32 soc_general_ctl;
+};
+
+static struct exynos5_dp * const exynos_dp0 = (void *)EXYNOS5_DP0_BASE;
+static struct exynos5_dp * const exynos_dp1 = (void *)EXYNOS5_DP1_BASE;
+
+/* 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);
+
+#endif
diff --git a/src/soc/samsung/exynos5250/dsim.h b/src/soc/samsung/exynos5250/dsim.h
new file mode 100644
index 0000000..b9245d3
--- /dev/null
+++ b/src/soc/samsung/exynos5250/dsim.h
@@ -0,0 +1,109 @@
+/*
+ * This file is part of the coreboot project.
+ *
+ * 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; 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
+ */
+
+/* Register map for Exynos5 MIPI-DSIM */
+
+#ifndef CPU_SAMSUNG_EXYNOS5250_DSIM_H
+#define CPU_SAMSUNG_EXYNOS5250_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/soc/samsung/exynos5250/fb.c b/src/soc/samsung/exynos5250/fb.c
new file mode 100644
index 0000000..080be49
--- /dev/null
+++ b/src/soc/samsung/exynos5250/fb.c
@@ -0,0 +1,578 @@
+/*
+ * This file is part of the coreboot project.
+ *
+ * Copyright 2013 Google Inc.
+ * 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; 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
+ */
+
+/* LCD driver for Exynos */
+
+#include <delay.h>
+#include <stdlib.h>
+#include <string.h>
+#include <timer.h>
+#include <arch/io.h>
+#include <console/console.h>
+#include "power.h"
+#include "sysreg.h"
+
+#include "dp.h"
+#include "dp-core.h"
+#include "fimd.h"
+#include "i2c.h"
+
+/*
+ * Here is the rough outline of how we bring up the display:
+ * 1. Upon power-on Sink generates a hot plug detection pulse thru HPD
+ * 2. Source determines video mode by reading DPCD receiver capability field
+ * (DPCD 00000h to 0000Dh) including eDP CP capability register (DPCD
+ * 0000Dh).
+ * 3. Sink replies DPCD receiver capability field.
+ * 4. Source starts EDID read thru I2C-over-AUX.
+ * 5. Sink replies EDID thru I2C-over-AUX.
+ * 6. Source determines link configuration, such as MAX_LINK_RATE and
+ * MAX_LANE_COUNT. Source also determines which type of eDP Authentication
+ * method to use and writes DPCD link configuration field (DPCD 00100h to
+ * 0010Ah) including eDP configuration set (DPCD 0010Ah).
+ * 7. Source starts link training. Sink does clock recovery and equalization.
+ * 8. Source reads DPCD link status field (DPCD 00200h to 0020Bh).
+ * 9. Sink replies DPCD link status field. If main link is not stable, Source
+ * repeats Step 7.
+ * 10. Source sends MSA (Main Stream Attribute) data. Sink extracts video
+ * parameters and recovers stream clock.
+ * 11. Source sends video data.
+ */
+
+/* To help debug any init errors here, define a list of possible errors */
+enum {
+ ERR_PLL_NOT_UNLOCKED = 2,
+ ERR_VIDEO_CLOCK_BAD,
+ ERR_VIDEO_STREAM_BAD,
+ ERR_DPCD_READ_ERROR1, /* 5 */
+
+ ERR_DPCD_WRITE_ERROR1,
+ ERR_DPCD_READ_ERROR2,
+ ERR_DPCD_WRITE_ERROR2,
+ ERR_INVALID_LANE,
+ ERR_PLL_NOT_LOCKED, /* 10 */
+
+ ERR_PRE_EMPHASIS_LEVELS,
+ ERR_LINK_RATE_ABNORMAL,
+ ERR_MAX_LANE_COUNT_ABNORMAL,
+ ERR_LINK_TRAINING_FAILURE,
+ ERR_MISSING_DP_BASE, /* 15 */
+
+ ERR_NO_FDT_NODE,
+};
+/* ok, this is stupid, but we're going to leave the variables in here until we
+ * know it works. One cleanup task at a time.
+ */
+enum stage_t {
+ STAGE_START = 0,
+ STAGE_LCD_VDD,
+ STAGE_BRIDGE_SETUP,
+ STAGE_BRIDGE_INIT,
+ STAGE_BRIDGE_RESET,
+ STAGE_HOTPLUG,
+ STAGE_DP_CONTROLLER,
+ STAGE_BACKLIGHT_VDD,
+ STAGE_BACKLIGHT_PWM,
+ STAGE_BACKLIGHT_EN,
+ STAGE_DONE,
+};
+
+int lcd_line_length;
+int lcd_color_fg;
+int lcd_color_bg;
+
+void *lcd_console_address; /* Start of console buffer */
+
+short console_col;
+short console_row;
+
+/* Bypass FIMD of DISP1_BLK */
+static void fimd_bypass(void)
+{
+ setbits_le32(&exynos_sysreg->disp1blk_cfg, FIMDBYPASS_DISP1);
+ exynos_sysreg->disp1blk_cfg &= ~FIMDBYPASS_DISP1;
+}
+
+/*
+ * Initialize display controller.
+ *
+ * @param lcdbase pointer to the base address of framebuffer.
+ * @pd pointer to the main panel_data structure
+ */
+void fb_init(unsigned long int fb_size, void *lcdbase,
+ struct exynos5_fimd_panel *pd)
+{
+ unsigned int val;
+
+ fb_size = ALIGN(fb_size, 4096);
+
+ writel(pd->ivclk | pd->fixvclk, &exynos_disp_ctrl->vidcon1);
+ val = ENVID_ON | ENVID_F_ON | (pd->clkval_f << CLKVAL_F_OFFSET);
+ writel(val, &exynos_fimd->vidcon0);
+
+ val = (pd->vsync << VSYNC_PULSE_WIDTH_OFFSET) |
+ (pd->lower_margin << V_FRONT_PORCH_OFFSET) |
+ (pd->upper_margin << V_BACK_PORCH_OFFSET);
+ writel(val, &exynos_disp_ctrl->vidtcon0);
+
+ val = (pd->hsync << HSYNC_PULSE_WIDTH_OFFSET) |
+ (pd->right_margin << H_FRONT_PORCH_OFFSET) |
+ (pd->left_margin << H_BACK_PORCH_OFFSET);
+ writel(val, &exynos_disp_ctrl->vidtcon1);
+
+ val = ((pd->xres - 1) << HOZVAL_OFFSET) |
+ ((pd->yres - 1) << LINEVAL_OFFSET);
+ writel(val, &exynos_disp_ctrl->vidtcon2);
+
+ writel((unsigned int)lcdbase, &exynos_fimd->vidw00add0b0);
+ writel((unsigned int)lcdbase + fb_size, &exynos_fimd->vidw00add1b0);
+
+ writel(pd->xres * 2, &exynos_fimd->vidw00add2);
+
+ val = ((pd->xres - 1) << OSD_RIGHTBOTX_F_OFFSET);
+ val |= ((pd->yres - 1) << OSD_RIGHTBOTY_F_OFFSET);
+ writel(val, &exynos_fimd->vidosd0b);
+ writel(pd->xres * pd->yres, &exynos_fimd->vidosd0c);
+
+ setbits_le32(&exynos_fimd->shadowcon, CHANNEL0_EN);
+
+ val = BPPMODE_F_RGB_16BIT_565 << BPPMODE_F_OFFSET;
+ val |= ENWIN_F_ENABLE | HALF_WORD_SWAP_EN;
+ writel(val, &exynos_fimd->wincon0);
+
+ /* DPCLKCON_ENABLE */
+ writel(1 << 1, &exynos_fimd->dpclkcon);
+}
+
+#ifdef UNUSED_CODE
+void exynos_fimd_disable(void)
+{
+ writel(0, &exynos_fimd->wincon0);
+ clrbits_le32(&exynos_fimd->shadowcon, CHANNEL0_EN);
+}
+#endif
+
+/*
+ * Configure DP in slave mode and wait for video stream.
+ *
+ * param dp pointer to main s5p-dp structure
+ * param video_info pointer to main video_info structure.
+ * return status
+ */
+static int s5p_dp_config_video(struct s5p_dp_device *dp,
+ struct video_info *video_info)
+{
+ int timeout = 0;
+ struct exynos5_dp *base = dp->base;
+ struct mono_time start, current, end;
+ s5p_dp_config_video_slave_mode(dp, video_info);
+
+ s5p_dp_set_video_color_format(dp, video_info->color_depth,
+ video_info->color_space,
+ video_info->dynamic_range,
+ video_info->ycbcr_coeff);
+
+ if (s5p_dp_get_pll_lock_status(dp) == PLL_UNLOCKED) {
+ printk(BIOS_DEBUG, "PLL is not locked yet.\n");
+ return -ERR_PLL_NOT_UNLOCKED;
+ }
+
+ timer_monotonic_get(&start);
+ end = current = start;
+ mono_time_add_usecs(&end, STREAM_ON_TIMEOUT * USECS_PER_MSEC);
+ do {
+ if (s5p_dp_is_slave_video_stream_clock_on(dp) == 0) {
+ timeout++;
+ break;
+ }
+ timer_monotonic_get(¤t);
+ } while (mono_time_before(¤t, &end));
+
+ if (!timeout) {
+ printk(BIOS_ERR, "Video Clock Not ok after %ldus.\n",
+ mono_time_diff_microseconds(&start, &end));
+ return -ERR_VIDEO_CLOCK_BAD;
+ }
+
+ /* Set to use the register calculated M/N video */
+ s5p_dp_set_video_cr_mn(dp, CALCULATED_M, 0, 0);
+
+ clrbits_le32(&base->video_ctl_10, FORMAT_SEL);
+
+ /* Disable video mute */
+ clrbits_le32(&base->video_ctl_1, HDCP_VIDEO_MUTE);
+
+ /* Configure video slave mode */
+ s5p_dp_enable_video_master(dp);
+
+ /* Enable video */
+ setbits_le32(&base->video_ctl_1, VIDEO_EN);
+ timeout = s5p_dp_is_video_stream_on(dp);
+
+ if (timeout) {
+ printk(BIOS_DEBUG, "Video Stream Not on\n");
+ return -ERR_VIDEO_STREAM_BAD;
+ }
+
+ return 0;
+}
+
+/*
+ * Set DP to enhanced mode. We use this for EVT1
+ * param dp pointer to main s5p-dp structure
+ * return status
+ */
+static int s5p_dp_enable_rx_to_enhanced_mode(struct s5p_dp_device *dp)
+{
+ u8 data;
+
+ if (s5p_dp_read_byte_from_dpcd(dp, DPCD_ADDR_LANE_COUNT_SET, &data)) {
+ printk(BIOS_DEBUG, "DPCD read error\n");
+ return -ERR_DPCD_READ_ERROR1;
+ }
+ if (s5p_dp_write_byte_to_dpcd(dp, DPCD_ADDR_LANE_COUNT_SET,
+ DPCD_ENHANCED_FRAME_EN |
+ (data & DPCD_LANE_COUNT_SET_MASK))) {
+ printk(BIOS_DEBUG, "DPCD write error\n");
+ return -ERR_DPCD_WRITE_ERROR1;
+ }
+
+ return 0;
+}
+
+/*
+ * Enable scrambles mode. We use this for EVT1
+ * param dp pointer to main s5p-dp structure
+ * return status
+ */
+static int s5p_dp_enable_scramble(struct s5p_dp_device *dp)
+{
+ u8 data;
+ struct exynos5_dp *base = dp->base;
+
+ clrbits_le32(&base->dp_training_ptn_set, SCRAMBLING_DISABLE);
+
+ if (s5p_dp_read_byte_from_dpcd(dp, DPCD_ADDR_TRAINING_PATTERN_SET,
+ &data)) {
+ printk(BIOS_DEBUG, "DPCD read error\n");
+ return -ERR_DPCD_READ_ERROR2;
+ }
+
+ if (s5p_dp_write_byte_to_dpcd(dp, DPCD_ADDR_TRAINING_PATTERN_SET,
+ (u8)(data & ~DPCD_SCRAMBLING_DISABLED))) {
+ printk(BIOS_DEBUG, "DPCD write error\n");
+ return -ERR_DPCD_WRITE_ERROR2;
+ }
+
+ return 0;
+}
+
+/*
+ * Reset DP and prepare DP for init training
+ * param dp pointer to main s5p-dp structure
+ */
+static int s5p_dp_init_dp(struct s5p_dp_device *dp)
+{
+ int ret, i;
+ struct exynos5_dp *base = dp->base;
+
+ for (i = 0; i < DP_INIT_TRIES; i++) {
+ s5p_dp_reset(dp);
+
+ /* SW defined function Normal operation */
+ clrbits_le32(&base->func_en_1, SW_FUNC_EN_N);
+
+ ret = s5p_dp_init_analog_func(dp);
+ if (!ret)
+ break;
+
+ udelay(5000);
+ printk(BIOS_DEBUG, "LCD retry init, attempt=%d ret=%d\n", i, ret);
+ }
+ if (i == DP_INIT_TRIES) {
+ printk(BIOS_DEBUG, "LCD initialization failed, ret=%d\n", ret);
+ return ret;
+ }
+
+ s5p_dp_init_aux(dp);
+
+ return ret;
+}
+
+/*
+ * Set pre-emphasis level
+ * param dp pointer to main s5p-dp structure
+ * param pre_emphasis pre-emphasis level
+ * param lane lane number(0 - 3)
+ * return status
+ */
+static int s5p_dp_set_lane_lane_pre_emphasis(struct s5p_dp_device *dp,
+ int pre_emphasis, int lane)
+{
+ u32 reg;
+ struct exynos5_dp *base = dp->base;
+
+ reg = pre_emphasis << PRE_EMPHASIS_SET_SHIFT;
+ switch (lane) {
+ case 0:
+ writel(reg, &base->ln0_link_trn_ctl);
+ break;
+ case 1:
+ writel(reg, &base->ln1_link_trn_ctl);
+ break;
+
+ case 2:
+ writel(reg, &base->ln2_link_trn_ctl);
+ break;
+
+ case 3:
+ writel(reg, &base->ln3_link_trn_ctl);
+ break;
+ default:
+ printk(BIOS_DEBUG, "%s: Invalid lane %d\n", __func__, lane);
+ return -ERR_INVALID_LANE;
+ }
+ return 0;
+}
+
+/*
+ * Read supported bandwidth type
+ * param dp pointer to main s5p-dp structure
+ * param bandwidth pointer to variable holding bandwidth type
+ */
+static void s5p_dp_get_max_rx_bandwidth(struct s5p_dp_device *dp,
+ u8 *bandwidth)
+{
+ u8 data;
+
+ /*
+ * For DP rev.1.1, Maximum link rate of Main Link lanes
+ * 0x06 = 1.62 Gbps, 0x0a = 2.7 Gbps
+ */
+ s5p_dp_read_byte_from_dpcd(dp, DPCD_ADDR_MAX_LINK_RATE, &data);
+ *bandwidth = data;
+}
+
+/*
+ * Reset DP and prepare DP for init training
+ * param dp pointer to main s5p-dp structure
+ * param lane_count pointer to variable holding no of lanes
+ */
+static void s5p_dp_get_max_rx_lane_count(struct s5p_dp_device *dp,
+ u8 *lane_count)
+{
+ u8 data;
+
+ /*
+ * For DP rev.1.1, Maximum number of Main Link lanes
+ * 0x01 = 1 lane, 0x02 = 2 lanes, 0x04 = 4 lanes
+ */
+ s5p_dp_read_byte_from_dpcd(dp, DPCD_ADDR_MAX_LANE_COUNT, &data);
+ *lane_count = data & DPCD_MAX_LANE_COUNT_MASK;
+}
+
+/*
+ * DP H/w Link Training. Set DPCD link rate and bandwidth.
+ * param dp pointer to main s5p-dp structure
+ * param max_lane No of lanes
+ * param max_rate bandwidth
+ * return status
+ */
+static int s5p_dp_hw_link_training(struct s5p_dp_device *dp,
+ unsigned int max_lane,
+ unsigned int max_rate)
+{
+ int pll_is_locked = 0;
+ u32 data;
+ int lane;
+ struct mono_time current, end;
+ struct exynos5_dp *base = dp->base;
+
+ /* Stop Video */
+ clrbits_le32(&base->video_ctl_1, VIDEO_EN);
+
+ timer_monotonic_get(¤t);
+ end = current;
+ mono_time_add_msecs(&end, PLL_LOCK_TIMEOUT);
+
+ while ((pll_is_locked = s5p_dp_get_pll_lock_status(dp)) == PLL_UNLOCKED) {
+ if (mono_time_after(¤t, &end)) {
+ /* Ignore this error, and try to continue */
+ printk(BIOS_ERR, "PLL is not locked yet.\n");
+ break;
+ }
+ timer_monotonic_get(¤t);
+ }
+ printk(BIOS_SPEW, "PLL is %slocked\n",
+ pll_is_locked == PLL_LOCKED ? "": "not ");
+ /* Reset Macro */
+ setbits_le32(&base->dp_phy_test, MACRO_RST);
+
+ /* 10 us is the minimum reset time. */
+ udelay(10);
+
+ clrbits_le32(&base->dp_phy_test, MACRO_RST);
+
+ /* Set TX pre-emphasis to minimum */
+ for (lane = 0; lane < max_lane; lane++)
+ if (s5p_dp_set_lane_lane_pre_emphasis(dp,
+ PRE_EMPHASIS_LEVEL_0, lane)) {
+ printk(BIOS_DEBUG, "Unable to set pre emphasis level\n");
+ return -ERR_PRE_EMPHASIS_LEVELS;
+ }
+
+ /* All DP analog module power up */
+ writel(0x00, &base->dp_phy_pd);
+
+ /* Initialize by reading RX's DPCD */
+ s5p_dp_get_max_rx_bandwidth(dp, &dp->link_train.link_rate);
+ s5p_dp_get_max_rx_lane_count(dp, &dp->link_train.lane_count);
+
+ printk(BIOS_SPEW, "%s: rate 0x%x, lane_count %d\n", __func__,
+ dp->link_train.link_rate, dp->link_train.lane_count);
+
+ if ((dp->link_train.link_rate != LINK_RATE_1_62GBPS) &&
+ (dp->link_train.link_rate != LINK_RATE_2_70GBPS)) {
+ printk(BIOS_DEBUG, "Rx Max Link Rate is abnormal :%x !\n",
+ dp->link_train.link_rate);
+ /* Not Retrying */
+ return -ERR_LINK_RATE_ABNORMAL;
+ }
+
+ if (dp->link_train.lane_count == 0) {
+ printk(BIOS_DEBUG, "Rx Max Lane count is abnormal :%x !\n",
+ dp->link_train.lane_count);
+ /* Not retrying */
+ return -ERR_MAX_LANE_COUNT_ABNORMAL;
+ }
+
+ /* Setup TX lane count & rate */
+ if (dp->link_train.lane_count > max_lane)
+ dp->link_train.lane_count = max_lane;
+ if (dp->link_train.link_rate > max_rate)
+ dp->link_train.link_rate = max_rate;
+
+ /* Set link rate and count as you want to establish*/
+ writel(dp->link_train.lane_count, &base->lane_count_set);
+ writel(dp->link_train.link_rate, &base->link_bw_set);
+
+ /* Set sink to D0 (Sink Not Ready) mode. */
+ s5p_dp_write_byte_to_dpcd(dp, DPCD_ADDR_SINK_POWER_STATE,
+ DPCD_SET_POWER_STATE_D0);
+
+ /* Start HW link training */
+ writel(HW_TRAINING_EN, &base->dp_hw_link_training);
+
+ /* Wait until HW link training done */
+ s5p_dp_wait_hw_link_training_done(dp);
+
+ /* Get hardware link training status */
+ data = readl(&base->dp_hw_link_training);
+ printk(BIOS_SPEW, "hardware link training status: 0x%08x\n", data);
+ if (data != 0) {
+ printk(BIOS_ERR, " H/W link training failure: 0x%x\n", data);
+ return -ERR_LINK_TRAINING_FAILURE;
+ }
+
+ /* Get Link Bandwidth */
+ data = readl(&base->link_bw_set);
+
+ dp->link_train.link_rate = data;
+
+ data = readl(&base->lane_count_set);
+ dp->link_train.lane_count = data;
+ printk(BIOS_SPEW, "Done training: Link bandwidth: 0x%x, lane_count: %d\n",
+ dp->link_train.link_rate, data);
+
+ return 0;
+}
+
+/*
+ * Initialize DP display
+ */
+int dp_controller_init(struct s5p_dp_device *dp_device)
+{
+ int ret;
+ struct s5p_dp_device *dp = dp_device;
+ struct exynos5_dp *base;
+
+ clock_init_dp_clock();
+
+ power_enable_dp_phy();
+ ret = s5p_dp_init_dp(dp);
+ if (ret) {
+ printk(BIOS_ERR, "%s: Could not initialize dp\n", __func__);
+ return ret;
+ }
+
+ ret = s5p_dp_hw_link_training(dp, dp->video_info->lane_count,
+ dp->video_info->link_rate);
+ if (ret) {
+ printk(BIOS_ERR, "unable to do link train\n");
+ return ret;
+ }
+ /* Minimum delay after H/w Link training */
+ udelay(1000);
+
+ ret = s5p_dp_enable_scramble(dp);
+ if (ret) {
+ printk(BIOS_ERR, "unable to set scramble mode\n");
+ return ret;
+ }
+
+ ret = s5p_dp_enable_rx_to_enhanced_mode(dp);
+ if (ret) {
+ printk(BIOS_ERR, "unable to set enhanced mode\n");
+ return ret;
+ }
+
+
+ base = dp->base;
+ /* Enable enhanced mode */
+ setbits_le32(&base->sys_ctl_4, ENHANCED);
+
+ writel(dp->link_train.lane_count, &base->lane_count_set);
+ writel(dp->link_train.link_rate, &base->link_bw_set);
+
+ s5p_dp_init_video(dp);
+ ret = s5p_dp_config_video(dp, dp->video_info);
+ if (ret) {
+ printk(BIOS_ERR, "unable to config video\n");
+ return ret;
+ }
+
+ return 0;
+}
+
+/**
+ * Init the LCD controller
+ *
+ * @param lcdbase Base address of LCD frame buffer
+ * @return 0 if ok, -ve error code on error
+ */
+int lcd_ctrl_init(unsigned long int fb_size,
+ struct exynos5_fimd_panel *panel_data, void *lcdbase)
+{
+ int ret = 0;
+
+ fimd_bypass();
+ fb_init(fb_size, lcdbase, panel_data);
+ return ret;
+}
diff --git a/src/soc/samsung/exynos5250/fimd.h b/src/soc/samsung/exynos5250/fimd.h
new file mode 100644
index 0000000..178fb73
--- /dev/null
+++ b/src/soc/samsung/exynos5250/fimd.h
@@ -0,0 +1,145 @@
+/*
+ * This file is part of the coreboot project.
+ *
+ * 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; 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
+ */
+
+/* Register map for Exynos5 FIMD */
+
+#ifndef CPU_SAMSUNG_EXYNOS5250_FIMD_H
+#define CPU_SAMSUNG_EXYNOS5250_FIMD_H
+
+#include "cpu.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;
+};
+
+static struct exynos5_fimd * const exynos_fimd = (void *)EXYNOS5_FIMD_BASE;
+
+#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; /* Horizontal Backporch */
+ unsigned int right_margin; /* Horizontal Frontporch */
+ unsigned int hsync; /* Horizontal Sync Pulse Width */
+ unsigned int xres; /* X Resolution */
+ unsigned int yres; /* Y Resolution */
+};
+
+/* 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;
+};
+
+static struct exynos5_disp_ctrl * const exynos_disp_ctrl =
+ (void *)EXYNOS5_DISP1_CTRL_BASE;
+
+#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/soc/samsung/exynos5250/gpio.c b/src/soc/samsung/exynos5250/gpio.c
new file mode 100644
index 0000000..2a93328
--- /dev/null
+++ b/src/soc/samsung/exynos5250/gpio.c
@@ -0,0 +1,279 @@
+/*
+ * This file is part of the coreboot project.
+ *
+ * Copyright (C) 2009 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; 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 <string.h>
+#include <delay.h>
+#include <assert.h>
+#include "gpio.h"
+#include "cpu.h"
+
+#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 */
+};
+
+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 },
+};
+
+/* This macro gets gpio pin offset from 0..7 */
+#define GPIO_BIT(x) ((x) & 0x7)
+
+static struct 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 gpio_bank *bank;
+
+ bank = (struct gpio_bank *)data->reg_addr;
+ bank += (gpio - upto) / GPIO_PER_BANK;
+ return bank;
+ }
+ }
+
+ ASSERT(gpio < GPIO_MAX_PORT); /* ...which it will not be */
+ return NULL;
+}
+
+/* Common GPIO API - only available on Exynos5 */
+void gpio_cfg_pin(int gpio, int cfg)
+{
+ unsigned int value;
+ struct 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 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 gpio_bank *bank = gpio_get_bank(gpio);
+
+ value = readl(&bank->pull);
+ value &= ~PULL_MASK(GPIO_BIT(gpio));
+
+ switch (mode) {
+ case GPIO_PULL_DOWN:
+ case 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 gpio_bank *bank = gpio_get_bank(gpio);
+
+ value = readl(&bank->drv);
+ value &= ~DRV_MASK(GPIO_BIT(gpio));
+
+ switch (mode) {
+ case GPIO_DRV_1X:
+ case GPIO_DRV_2X:
+ case GPIO_DRV_3X:
+ case 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 gpio_bank *bank = gpio_get_bank(gpio);
+
+ value = readl(&bank->drv);
+ value &= ~RATE_MASK(GPIO_BIT(gpio));
+
+ switch (mode) {
+ case GPIO_DRV_FAST:
+ case GPIO_DRV_SLOW:
+ value |= RATE_SET(GPIO_BIT(gpio));
+ break;
+ default:
+ return;
+ }
+
+ writel(value, &bank->drv);
+}
+
+int gpio_direction_input(unsigned gpio)
+{
+ gpio_cfg_pin(gpio, GPIO_INPUT);
+
+ return 0;
+}
+
+int gpio_direction_output(unsigned gpio, int value)
+{
+ unsigned int val;
+ struct 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);
+
+ gpio_cfg_pin(gpio, GPIO_OUTPUT);
+
+ return 0;
+}
+
+int gpio_get_value(unsigned gpio)
+{
+ unsigned int value;
+ struct 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 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;
+}
+
+/*
+ * 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
+
+#ifndef __BOOT_BLOCK__
+/*
+ * FIXME(dhendrix): These functions use udelay, which has dependencies on
+ * pwm code and timer code. These aren't necessary for the bootblock and
+ * bloat the image significantly.
+ */
+int gpio_read_mvl3(unsigned gpio)
+{
+ int high, low;
+ enum mvl3 value;
+
+ if (gpio >= GPIO_MAX_PORT)
+ return -1;
+
+ gpio_direction_input(gpio);
+ gpio_set_pull(gpio, GPIO_PULL_UP);
+ udelay(GPIO_DELAY_US);
+ high = gpio_get_value(gpio);
+ gpio_set_pull(gpio, GPIO_PULL_DOWN);
+ udelay(GPIO_DELAY_US);
+ low = gpio_get_value(gpio);
+
+ if (high && low) /* external pullup */
+ value = LOGIC_1;
+ else if (!high && !low) /* external pulldown */
+ value = LOGIC_0;
+ else /* floating */
+ value = LOGIC_Z;
+
+ /*
+ * 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 == LOGIC_1)
+ gpio_set_pull(gpio, GPIO_PULL_UP);
+
+ return value;
+}
+#endif /* __BOOT_BLOCK__ */
+
+/*
+ * 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: ", gpio);
+ if (cfg == GPIO_INPUT)
+ printk(BIOS_INFO, "input");
+ else if (cfg == GPIO_OUTPUT)
+ printk(BIOS_INFO, "output");
+ else
+ printk(BIOS_INFO, "func %d", cfg);
+
+ if (cfg == GPIO_INPUT || cfg == GPIO_OUTPUT)
+ printk(BIOS_INFO, ", value = %d", gpio_get_value(gpio));
+ printk(BIOS_INFO, "\n");
+ }
+}
diff --git a/src/soc/samsung/exynos5250/gpio.h b/src/soc/samsung/exynos5250/gpio.h
new file mode 100644
index 0000000..a8f22f7
--- /dev/null
+++ b/src/soc/samsung/exynos5250/gpio.h
@@ -0,0 +1,567 @@
+/*
+ * This file is part of the coreboot project.
+ *
+ * Copyright (C) 2010 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; 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
+ */
+
+#ifndef CPU_SAMSUNG_EXYNOS5250_GPIO_H
+#define CPU_SAMSUNG_EXYNOS5250_GPIO_H
+
+#include "cpu.h"
+
+struct 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];
+};
+
+/* GPIO pins per bank */
+#define GPIO_PER_BANK 8
+
+/* Pin configurations */
+#define GPIO_INPUT 0x0
+#define GPIO_OUTPUT 0x1
+#define GPIO_IRQ 0xf
+#define GPIO_FUNC(x) (x)
+
+/* Pull mode */
+#define GPIO_PULL_NONE 0x0
+#define GPIO_PULL_DOWN 0x1
+#define GPIO_PULL_UP 0x3
+
+/* Drive Strength level */
+#define GPIO_DRV_1X 0x0
+#define GPIO_DRV_3X 0x1
+#define GPIO_DRV_2X 0x2
+#define GPIO_DRV_4X 0x3
+#define GPIO_DRV_FAST 0x0
+#define GPIO_DRV_SLOW 0x1
+
+enum exynos5_gpio_port {
+ EXYNOS5_GPA0 = EXYNOS5_GPIO_PART1_BASE + 0x0000,
+ EXYNOS5_GPA1 = EXYNOS5_GPIO_PART1_BASE + 0x0020,
+ EXYNOS5_GPA2 = EXYNOS5_GPIO_PART1_BASE + 0x0040,
+
+ EXYNOS5_GPB0 = EXYNOS5_GPIO_PART1_BASE + 0x0060,
+ EXYNOS5_GPB1 = EXYNOS5_GPIO_PART1_BASE + 0x0080,
+ EXYNOS5_GPB2 = EXYNOS5_GPIO_PART1_BASE + 0x00a0,
+ EXYNOS5_GPB3 = EXYNOS5_GPIO_PART1_BASE + 0x00c0,
+
+ EXYNOS5_GPC0 = EXYNOS5_GPIO_PART1_BASE + 0x00e0,
+ EXYNOS5_GPC1 = EXYNOS5_GPIO_PART1_BASE + 0x0100,
+ EXYNOS5_GPC2 = EXYNOS5_GPIO_PART1_BASE + 0x0120,
+ EXYNOS5_GPC3 = EXYNOS5_GPIO_PART1_BASE + 0x0140,
+
+ EXYNOS5_GPD0 = EXYNOS5_GPIO_PART1_BASE + 0x0160,
+ EXYNOS5_GPD1 = EXYNOS5_GPIO_PART1_BASE + 0x0180,
+
+ EXYNOS5_GPY0 = EXYNOS5_GPIO_PART1_BASE + 0x01a0,
+ EXYNOS5_GPY1 = EXYNOS5_GPIO_PART1_BASE + 0x01c0,
+ EXYNOS5_GPY2 = EXYNOS5_GPIO_PART1_BASE + 0x01e0,
+ EXYNOS5_GPY3 = EXYNOS5_GPIO_PART1_BASE + 0x0200,
+ EXYNOS5_GPY4 = EXYNOS5_GPIO_PART1_BASE + 0x0220,
+ EXYNOS5_GPY5 = EXYNOS5_GPIO_PART1_BASE + 0x0240,
+ EXYNOS5_GPY6 = EXYNOS5_GPIO_PART1_BASE + 0x0260,
+
+ EXYNOS5_GPX0 = EXYNOS5_GPIO_PART2_BASE + 0x0000,
+ EXYNOS5_GPX1 = EXYNOS5_GPIO_PART2_BASE + 0x0020,
+ EXYNOS5_GPX2 = EXYNOS5_GPIO_PART2_BASE + 0x0040,
+ EXYNOS5_GPX3 = EXYNOS5_GPIO_PART2_BASE + 0x0060,
+
+ EXYNOS5_GPE0 = EXYNOS5_GPIO_PART3_BASE + 0x0000,
+ EXYNOS5_GPE1 = EXYNOS5_GPIO_PART3_BASE + 0x0020,
+
+ EXYNOS5_GPF0 = EXYNOS5_GPIO_PART3_BASE + 0x0040,
+ EXYNOS5_GPF1 = EXYNOS5_GPIO_PART3_BASE + 0x0060,
+
+ EXYNOS5_GPG0 = EXYNOS5_GPIO_PART3_BASE + 0x0080,
+ EXYNOS5_GPG1 = EXYNOS5_GPIO_PART3_BASE + 0x00a0,
+ EXYNOS5_GPG2 = EXYNOS5_GPIO_PART3_BASE + 0x00c0,
+
+ EXYNOS5_GPH0 = EXYNOS5_GPIO_PART3_BASE + 0x00e0,
+ EXYNOS5_GPH1 = EXYNOS5_GPIO_PART3_BASE + 0x0100,
+
+ EXYNOS5_GPV0 = EXYNOS5_GPIO_PART4_BASE + 0x0000,
+ EXYNOS5_GPV1 = EXYNOS5_GPIO_PART4_BASE + 0x0020,
+ EXYNOS5_GPV2 = EXYNOS5_GPIO_PART4_BASE + 0x0060,
+ EXYNOS5_GPV3 = EXYNOS5_GPIO_PART4_BASE + 0x0080,
+
+ EXYNOS5_GPV4 = EXYNOS5_GPIO_PART5_BASE + 0x0000,
+
+ EXYNOS5_GPZ = EXYNOS5_GPIO_PART6_BASE + 0x0000,
+};
+
+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
+};
+
+/**
+ * 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);
+
+/*
+ * reads only a single GPIO
+ *
+ * @param gpio GPIO to read
+ * @return -1 if the value cannot be determined. Otherwise returns
+ * the corresponding MVL3 enum value.
+ */
+int gpio_read_mvl3(unsigned gpio);
+
+void gpio_info(void);
+
+/*
+ * 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.
+ */
+
+/**
+ * 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);
+
+/*
+ * Many-value logic (3 states). This can be used for inputs whereby presence
+ * of external pull-up or pull-down resistors can be added to overcome internal
+ * pull-ups/pull-downs and force a single value.
+ *
+ * Thus, external pull resistors can force a 0 or 1 and if the value changes
+ * along with internal pull-up/down enable then the input is floating.
+ *
+ * Vpd | Vpu | MVL
+ * -----------------
+ * 0 | 0 | 0
+ * -----------------
+ * 0 | 1 | Z <-- floating input will follow internal pull up/down
+ * -----------------
+ * 1 | 1 | 1
+ */
+enum mvl3 {
+ LOGIC_0,
+ LOGIC_1,
+ LOGIC_Z, /* high impedence / tri-stated / floating */
+};
+
+#endif /* CPU_SAMSUNG_EXYNOS5250_GPIO_H */
diff --git a/src/soc/samsung/exynos5250/i2c.c b/src/soc/samsung/exynos5250/i2c.c
new file mode 100644
index 0000000..e83ab57
--- /dev/null
+++ b/src/soc/samsung/exynos5250/i2c.c
@@ -0,0 +1,403 @@
+/*
+ * This file is part of the coreboot project.
+ *
+ * (C) Copyright 2002
+ * David Mueller, ELSOFT AG, d.mueller@elsoft.ch
+ *
+ * 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 <delay.h>
+#include <arch/io.h>
+#include <device/i2c.h>
+#include "clk.h"
+#include "i2c.h"
+
+#define I2C_WRITE 0
+#define I2C_READ 1
+
+#define I2C_OK 0
+#define I2C_NOK 1
+#define I2C_NACK 2
+#define I2C_NOK_LA 3 /* Lost arbitration */
+#define I2C_NOK_TOUT 4 /* time out */
+
+#define I2CSTAT_BSY 0x20 /* Busy bit */
+#define I2CSTAT_NACK 0x01 /* Nack bit */
+#define I2CCON_ACKGEN 0x80 /* Acknowledge generation */
+#define I2CCON_IRPND 0x10 /* Interrupt pending bit */
+#define I2C_MODE_MT 0xC0 /* Master Transmit Mode */
+#define I2C_MODE_MR 0x80 /* Master Receive Mode */
+#define I2C_START_STOP 0x20 /* START / STOP */
+#define I2C_TXRX_ENA 0x10 /* I2C Tx/Rx enable */
+
+/* The timeouts we live by */
+enum {
+ I2C_XFER_TIMEOUT_MS = 35, /* xfer to complete */
+ I2C_INIT_TIMEOUT_MS = 1000, /* bus free on init */
+ I2C_IDLE_TIMEOUT_MS = 100, /* waiting for bus idle */
+ I2C_STOP_TIMEOUT_US = 200, /* waiting for stop events */
+};
+
+static struct s3c24x0_i2c_bus i2c_buses[] = {
+ {
+ .bus_num = 0,
+ .regs = (struct s3c24x0_i2c *)0x12c60000,
+ .periph_id = PERIPH_ID_I2C0,
+ },
+ {
+ .bus_num = 1,
+ .regs = (struct s3c24x0_i2c *)0x12c70000,
+ .periph_id = PERIPH_ID_I2C1,
+ },
+ {
+ .bus_num = 2,
+ .regs = (struct s3c24x0_i2c *)0x12c80000,
+ .periph_id = PERIPH_ID_I2C2,
+ },
+ {
+ .bus_num = 3,
+ .regs = (struct s3c24x0_i2c *)0x12c90000,
+ .periph_id = PERIPH_ID_I2C3,
+ },
+ {
+ .bus_num = 4,
+ .regs = (struct s3c24x0_i2c *)0x12ca0000,
+ .periph_id = PERIPH_ID_I2C4,
+ },
+ {
+ .bus_num = 5,
+ .regs = (struct s3c24x0_i2c *)0x12cb0000,
+ .periph_id = PERIPH_ID_I2C5,
+ },
+ {
+ .bus_num = 6,
+ .regs = (struct s3c24x0_i2c *)0x12cc0000,
+ .periph_id = PERIPH_ID_I2C6,
+ },
+ {
+ .bus_num = 7,
+ .regs = (struct s3c24x0_i2c *)0x12cd0000,
+ .periph_id = PERIPH_ID_I2C7,
+ },
+};
+
+static int WaitForXfer(struct s3c24x0_i2c *i2c)
+{
+ int i;
+
+ i = I2C_XFER_TIMEOUT_MS * 20;
+ while (!(readl(&i2c->iiccon) & I2CCON_IRPND)) {
+ if (i == 0) {
+ printk(BIOS_ERR, "%s: i2c xfer timeout\n", __func__);
+ return I2C_NOK_TOUT;
+ }
+ udelay(50);
+ i--;
+ }
+
+ return I2C_OK;
+}
+
+static int IsACK(struct s3c24x0_i2c *i2c)
+{
+ return !(readl(&i2c->iicstat) & I2CSTAT_NACK);
+}
+
+static void ReadWriteByte(struct s3c24x0_i2c *i2c)
+{
+ uint32_t x;
+
+ x = readl(&i2c->iiccon);
+ writel(x & ~I2CCON_IRPND, &i2c->iiccon);
+}
+
+static void i2c_ch_init(struct s3c24x0_i2c_bus *bus, int speed, int slaveadd)
+{
+ unsigned long freq, pres = 16, div;
+ unsigned long val;
+
+ freq = clock_get_periph_rate(bus->periph_id);
+ /* calculate prescaler and divisor values */
+ if ((freq / pres / (16 + 1)) > speed)
+ /* set prescaler to 512 */
+ pres = 512;
+
+ div = 0;
+
+ while ((freq / pres / (div + 1)) > speed)
+ div++;
+
+ /* set prescaler, divisor according to freq, also set ACKGEN, IRQ */
+ val = (div & 0x0F) | 0xA0 | ((pres == 512) ? 0x40 : 0);
+ writel(val, &bus->regs->iiccon);
+
+ /* init to SLAVE RECEIVE mode and clear I2CADDn */
+ writel(0, &bus->regs->iicstat);
+ writel(slaveadd, &bus->regs->iicadd);
+ /* program Master Transmit (and implicit STOP) */
+ writel(I2C_MODE_MT | I2C_TXRX_ENA, &bus->regs->iicstat);
+}
+
+/*
+ * MULTI BUS I2C support
+ */
+static void i2c_bus_init(struct s3c24x0_i2c_bus *bus, int speed, int slaveadd)
+{
+ i2c_ch_init(bus, speed, slaveadd);
+}
+
+/*
+ * Verify the whether I2C ACK was received or not
+ *
+ * @param i2c pointer to I2C register base
+ * @param buf array of data
+ * @param len length of data
+ * return I2C_OK when transmission done
+ * I2C_NACK otherwise
+ */
+static int i2c_send_verify(struct s3c24x0_i2c *i2c, unsigned char buf[],
+ unsigned char len)
+{
+ int i, result = I2C_OK;
+
+ if (IsACK(i2c)) {
+ for (i = 0; (i < len) && (result == I2C_OK); i++) {
+ writel(buf[i], &i2c->iicds);
+ ReadWriteByte(i2c);
+ result = WaitForXfer(i2c);
+ if (result == I2C_OK && !IsACK(i2c))
+ result = I2C_NACK;
+ }
+ } else {
+ result = I2C_NACK;
+ }
+
+ return result;
+}
+
+void i2c_init(unsigned bus_num, int speed, int slaveadd)
+{
+ struct s3c24x0_i2c_bus *i2c;
+ int i;
+
+ i2c = &i2c_buses[bus_num];
+ i2c_bus_init(i2c, speed, slaveadd);
+
+ /* wait for some time to give previous transfer a chance to finish */
+ i = I2C_INIT_TIMEOUT_MS * 20;
+ while ((readl(&i2c->regs->iicstat) & I2CSTAT_BSY) && (i > 0)) {
+ udelay(50);
+ i--;
+ }
+
+ i2c_ch_init(i2c, speed, slaveadd);
+}
+
+/*
+ * Send a STOP event and wait for it to have completed
+ *
+ * @param mode If it is a master transmitter or receiver
+ * @return I2C_OK if the line became idle before timeout I2C_NOK_TOUT otherwise
+ */
+static int i2c_send_stop(struct s3c24x0_i2c *i2c, int mode)
+{
+ int timeout;
+
+ /* Setting the STOP event to fire */
+ writel(mode | I2C_TXRX_ENA, &i2c->iicstat);
+ ReadWriteByte(i2c);
+
+ /* Wait for the STOP to send and the bus to go idle */
+ for (timeout = I2C_STOP_TIMEOUT_US; timeout > 0; timeout -= 5) {
+ if (!(readl(&i2c->iicstat) & I2CSTAT_BSY))
+ return I2C_OK;
+ udelay(5);
+ }
+
+ return I2C_NOK_TOUT;
+}
+
+/*
+ * cmd_type is 0 for write, 1 for read.
+ *
+ * addr_len can take any value from 0-255, it is only limited
+ * by the char, we could make it larger if needed. If it is
+ * 0 we skip the address write cycle.
+ */
+static int i2c_transfer(struct s3c24x0_i2c *i2c,
+ unsigned char cmd_type,
+ unsigned char chip,
+ unsigned char addr[],
+ unsigned char addr_len,
+ unsigned char data[],
+ unsigned short data_len)
+{
+ int i, result, stop_bit_result;
+ uint32_t x;
+
+ if (data == 0 || data_len == 0) {
+ /* Don't support data transfer of no length or to address 0 */
+ printk(BIOS_ERR, "i2c_transfer: bad call\n");
+ return I2C_NOK;
+ }
+
+ /* Check I2C bus idle */
+ i = I2C_IDLE_TIMEOUT_MS * 20;
+ while ((readl(&i2c->iicstat) & I2CSTAT_BSY) && (i > 0)) {
+ udelay(50);
+ i--;
+ }
+
+ if (readl(&i2c->iicstat) & I2CSTAT_BSY) {
+ printk(BIOS_ERR, "%s: bus busy\n", __func__);
+ return I2C_NOK_TOUT;
+ }
+
+ x = readl(&i2c->iiccon);
+ writel(x | I2CCON_ACKGEN, &i2c->iiccon);
+
+ if (addr && addr_len) {
+ writel(chip, &i2c->iicds);
+ /* send START */
+ writel(I2C_MODE_MT | I2C_TXRX_ENA | I2C_START_STOP,
+ &i2c->iicstat);
+ if (WaitForXfer(i2c) == I2C_OK)
+ result = i2c_send_verify(i2c, addr, addr_len);
+ else
+ result = I2C_NACK;
+ } else
+ result = I2C_NACK;
+
+ switch (cmd_type) {
+ case I2C_WRITE:
+ if (result == I2C_OK)
+ result = i2c_send_verify(i2c, data, data_len);
+ else {
+ writel(chip, &i2c->iicds);
+ /* send START */
+ writel(I2C_MODE_MT | I2C_TXRX_ENA | I2C_START_STOP,
+ &i2c->iicstat);
+ if (WaitForXfer(i2c) == I2C_OK)
+ result = i2c_send_verify(i2c, data, data_len);
+ }
+
+ if (result == I2C_OK)
+ result = WaitForXfer(i2c);
+
+ stop_bit_result = i2c_send_stop(i2c, I2C_MODE_MT);
+ break;
+
+ case I2C_READ:
+ {
+ int was_ok = (result == I2C_OK);
+
+ writel(chip, &i2c->iicds);
+ /* resend START */
+ writel(I2C_MODE_MR | I2C_TXRX_ENA |
+ I2C_START_STOP, &i2c->iicstat);
+ ReadWriteByte(i2c);
+ result = WaitForXfer(i2c);
+
+ if (was_ok || IsACK(i2c)) {
+ i = 0;
+ while ((i < data_len) && (result == I2C_OK)) {
+ /* disable ACK for final READ */
+ if (i == data_len - 1) {
+ x = readl(&i2c->iiccon) & ~I2CCON_ACKGEN;
+ writel(x, &i2c->iiccon);
+ }
+ ReadWriteByte(i2c);
+ result = WaitForXfer(i2c);
+ data[i] = readl(&i2c->iicds);
+ i++;
+ }
+ } else {
+ result = I2C_NACK;
+ }
+
+ stop_bit_result = i2c_send_stop(i2c, I2C_MODE_MR);
+ break;
+ }
+
+ default:
+ printk(BIOS_ERR, "i2c_transfer: bad call\n");
+ result = stop_bit_result = I2C_NOK;
+ break;
+ }
+
+ /*
+ * If the transmission went fine, then only the stop bit was left to
+ * fail. Otherwise, the real failure we're interested in came before
+ * that, during the actual transmission.
+ */
+ return (result == I2C_OK) ? stop_bit_result : result;
+}
+
+int i2c_read(unsigned bus, unsigned chip, unsigned addr,
+ unsigned alen, uint8_t *buf, unsigned len)
+{
+ struct s3c24x0_i2c_bus *i2c;
+ unsigned char xaddr[4];
+ int ret;
+
+ if (alen > 4) {
+ printk(BIOS_ERR, "I2C read: addr len %d not supported\n", alen);
+ return 1;
+ }
+
+ if (alen > 0) {
+ xaddr[0] = (addr >> 24) & 0xFF;
+ xaddr[1] = (addr >> 16) & 0xFF;
+ xaddr[2] = (addr >> 8) & 0xFF;
+ xaddr[3] = addr & 0xFF;
+ }
+
+ i2c = &i2c_buses[bus];
+ ret = i2c_transfer(i2c->regs, I2C_READ, chip << 1, &xaddr[4 - alen],
+ alen, buf, len);
+ if (ret) {
+ printk(BIOS_ERR, "I2c read: failed %d\n", ret);
+ return 1;
+ }
+ return 0;
+}
+
+int i2c_write(unsigned bus, unsigned chip, unsigned addr,
+ unsigned alen, const uint8_t *buf, unsigned len)
+{
+ struct s3c24x0_i2c_bus *i2c;
+ unsigned char xaddr[4];
+ int ret;
+
+ if (alen > 4) {
+ printk(BIOS_ERR, "I2C write: addr len %d not supported\n",
+ alen);
+ return 1;
+ }
+
+ if (alen > 0) {
+ xaddr[0] = (addr >> 24) & 0xFF;
+ xaddr[1] = (addr >> 16) & 0xFF;
+ xaddr[2] = (addr >> 8) & 0xFF;
+ xaddr[3] = addr & 0xFF;
+ }
+
+ i2c = &i2c_buses[bus];
+ ret = i2c_transfer(i2c->regs, I2C_WRITE, chip << 1, &xaddr[4 - alen],
+ alen, (void *)buf, len);
+
+ return ret != 0;
+}
diff --git a/src/soc/samsung/exynos5250/i2c.h b/src/soc/samsung/exynos5250/i2c.h
new file mode 100644
index 0000000..a1d8bc1
--- /dev/null
+++ b/src/soc/samsung/exynos5250/i2c.h
@@ -0,0 +1,41 @@
+/*
+ * This file is part of the coreboot project.
+ *
+ * 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; 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
+ */
+
+#ifndef CPU_SAMSUNG_EXYNOS5250_I2C_H
+#define CPU_SAMSUNG_EXYNOS5250_I2C_H
+
+#include "periph.h"
+
+struct s3c24x0_i2c {
+ u32 iiccon;
+ u32 iicstat;
+ u32 iicadd;
+ u32 iicds;
+ u32 iiclc;
+};
+
+struct s3c24x0_i2c_bus {
+ int bus_num;
+ struct s3c24x0_i2c *regs;
+ enum periph_id periph_id;
+};
+
+void i2c_init(unsigned bus, int speed, int slaveadd);
+
+#endif /* CPU_SAMSUNG_EXYNOS5250_I2C_H */
diff --git a/src/soc/samsung/exynos5250/i2s-regs.h b/src/soc/samsung/exynos5250/i2s-regs.h
new file mode 100644
index 0000000..fabd914
--- /dev/null
+++ b/src/soc/samsung/exynos5250/i2s-regs.h
@@ -0,0 +1,142 @@
+/*
+ * This file is part of the coreboot project.
+ *
+ * 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; 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
+ */
+
+/* Taken from the kernel code */
+
+#ifndef CPU_SAMSUNG_EXYNOS5250_I2S_REGS_H
+#define CPU_SAMSUNG_EXYNOS5250_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 /* CPU_SAMSUNG_EXYNOS5250_I2S_REGS_H */
diff --git a/src/soc/samsung/exynos5250/mct.c b/src/soc/samsung/exynos5250/mct.c
new file mode 100644
index 0000000..bbb90e4
--- /dev/null
+++ b/src/soc/samsung/exynos5250/mct.c
@@ -0,0 +1,36 @@
+/*
+ * This file is part of the coreboot project.
+ *
+ * Copyright 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
+ */
+
+#include <stdint.h>
+#include <arch/io.h>
+#include "clk.h"
+
+uint64_t mct_raw_value(void)
+{
+ uint64_t upper = readl(&exynos_mct->g_cnt_u);
+ uint64_t lower = readl(&exynos_mct->g_cnt_l);
+
+ return (upper << 32) | lower;
+}
+
+void mct_start(void)
+{
+ writel(readl(&exynos_mct->g_tcon) | (0x1 << 8),
+ &exynos_mct->g_tcon);
+}
diff --git a/src/soc/samsung/exynos5250/monotonic_timer.c b/src/soc/samsung/exynos5250/monotonic_timer.c
new file mode 100644
index 0000000..89ac416
--- /dev/null
+++ b/src/soc/samsung/exynos5250/monotonic_timer.c
@@ -0,0 +1,34 @@
+/*
+ * This file is part of the coreboot project.
+ *
+ * Copyright 2013 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 <stdint.h>
+#include <timer.h>
+
+#include "clk.h"
+
+static const uint32_t clocks_per_usec = MCT_HZ/1000000;
+
+void timer_monotonic_get(struct mono_time *mt)
+{
+ /* We don't have to call mct_start() here
+ * because it was already called in the bootblock
+ */
+
+ mono_time_set_usecs(mt, mct_raw_value() / clocks_per_usec);
+}
diff --git a/src/soc/samsung/exynos5250/periph.h b/src/soc/samsung/exynos5250/periph.h
new file mode 100644
index 0000000..7d8bf62
--- /dev/null
+++ b/src/soc/samsung/exynos5250/periph.h
@@ -0,0 +1,69 @@
+/*
+ * This file is part of the coreboot project.
+ *
+ * Copyright 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
+ */
+
+#ifndef CPU_SAMSUNG_EXYNOS5250_PERIPH_H
+#define CPU_SAMSUNG_EXYNOS5250_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,
+
+ 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/soc/samsung/exynos5250/pinmux.c b/src/soc/samsung/exynos5250/pinmux.c
new file mode 100644
index 0000000..dc9590f
--- /dev/null
+++ b/src/soc/samsung/exynos5250/pinmux.c
@@ -0,0 +1,267 @@
+/*
+ * This file is part of the coreboot project.
+ *
+ * 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; 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 <assert.h>
+#include "gpio.h"
+#include "pinmux.h"
+
+static void exynos_pinmux_uart(int start, int count)
+{
+ int i;
+
+ for (i = start; i < start + count; i++) {
+ gpio_set_pull(i, GPIO_PULL_NONE);
+ gpio_cfg_pin(i, GPIO_FUNC(0x2));
+ }
+}
+
+void exynos_pinmux_uart0(void)
+{
+ exynos_pinmux_uart(GPIO_A00, 4);
+}
+
+void exynos_pinmux_uart1(void)
+{
+ exynos_pinmux_uart(GPIO_D00, 4);
+}
+
+void exynos_pinmux_uart2(void)
+{
+ exynos_pinmux_uart(GPIO_A10, 4);
+}
+
+void exynos_pinmux_uart3(void)
+{
+ exynos_pinmux_uart(GPIO_A14, 2);
+}
+
+static void exynos_pinmux_sdmmc(int start, int start_ext)
+{
+ int i;
+
+ if (start_ext) {
+ for (i = 0; i <= 3; i++) {
+ gpio_cfg_pin(start_ext + i, GPIO_FUNC(0x2));
+ gpio_set_pull(start_ext + i, GPIO_PULL_UP);
+ gpio_set_drv(start_ext + i, GPIO_DRV_4X);
+ }
+ }
+ for (i = 0; i < 2; i++) {
+ gpio_cfg_pin(start + i, GPIO_FUNC(0x2));
+ gpio_set_pull(start + i, GPIO_PULL_NONE);
+ gpio_set_drv(start + i, GPIO_DRV_4X);
+ }
+ for (i = 2; i <= 6; i++) {
+ gpio_cfg_pin(start + i, GPIO_FUNC(0x2));
+ gpio_set_pull(start + i, GPIO_PULL_UP);
+ gpio_set_drv(start + i, GPIO_DRV_4X);
+ }
+}
+
+void exynos_pinmux_sdmmc0(void)
+{
+ exynos_pinmux_sdmmc(GPIO_C00, GPIO_C10);
+}
+
+void exynos_pinmux_sdmmc1(void)
+{
+ exynos_pinmux_sdmmc(GPIO_C20, 0);
+}
+
+void exynos_pinmux_sdmmc2(void)
+{
+ exynos_pinmux_sdmmc(GPIO_C30, 0);
+}
+
+void exynos_pinmux_sdmmc3(void)
+{
+ /*
+ * TODO: Need to add definitions for GPC4 before
+ * enabling this.
+ */
+ printk(BIOS_DEBUG, "SDMMC3 not supported yet");
+}
+
+void exynos_pinmux_sromc(int bank, int sixteen_bit)
+{
+ int i;
+
+ if (bank > 3) {
+ printk(BIOS_DEBUG, "Unsupported sromc bank %d.\n", bank);
+ return;
+ }
+
+ gpio_cfg_pin(GPIO_Y00 + bank, GPIO_FUNC(2));
+ gpio_cfg_pin(GPIO_Y04, GPIO_FUNC(2));
+ gpio_cfg_pin(GPIO_Y05, GPIO_FUNC(2));
+
+ for (i = 2; i < 4; i++)
+ gpio_cfg_pin(GPIO_Y10 + i, GPIO_FUNC(2));
+
+ for (i = 0; i < 8; i++) {
+ gpio_cfg_pin(GPIO_Y30 + i, GPIO_FUNC(2));
+ gpio_set_pull(GPIO_Y30 + i, GPIO_PULL_UP);
+
+ gpio_cfg_pin(GPIO_Y50 + i, GPIO_FUNC(2));
+ gpio_set_pull(GPIO_Y50 + i, GPIO_PULL_UP);
+
+ if (sixteen_bit) {
+ gpio_cfg_pin(GPIO_Y60 + i, GPIO_FUNC(2));
+ gpio_set_pull(GPIO_Y60 + i, GPIO_PULL_UP);
+ }
+ }
+}
+
+static void exynos_pinmux_spi(int start, int cfg)
+{
+ int i;
+
+ for (i = 0; i < 4; i++) {
+ gpio_cfg_pin(start + i, GPIO_FUNC(cfg));
+ gpio_set_pull(start + i, GPIO_PULL_NONE);
+ gpio_set_drv(start + i, GPIO_DRV_3X);
+ }
+}
+
+void exynos_pinmux_spi0(void)
+{
+ exynos_pinmux_spi(GPIO_A20, 0x2);
+}
+
+void exynos_pinmux_spi1(void)
+{
+ exynos_pinmux_spi(GPIO_A24, 0x2);
+}
+
+void exynos_pinmux_spi2(void)
+{
+ exynos_pinmux_spi(GPIO_B11, 0x5);
+}
+
+void exynos_pinmux_spi3(void)
+{
+ exynos_pinmux_spi(GPIO_E00, 0x2);
+}
+
+void exynos_pinmux_spi4(void)
+{
+ int i;
+
+ for (i = 0; i < 2; i++)
+ gpio_cfg_pin(GPIO_F02 + i, GPIO_FUNC(0x4));
+ for (i = 2; i < 4; i++)
+ gpio_cfg_pin(GPIO_E02 + i, GPIO_FUNC(0x4));
+}
+
+void exynos_pinmux_backlight(void)
+{
+ gpio_cfg_pin(GPIO_B20, GPIO_OUTPUT);
+ gpio_set_value(GPIO_B20, 1);
+}
+
+void exynos_pinmux_lcd(void)
+{
+ gpio_cfg_pin(GPIO_Y25, GPIO_OUTPUT);
+ gpio_set_value(GPIO_Y25, 1);
+ gpio_cfg_pin(GPIO_X15, GPIO_OUTPUT);
+ gpio_set_value(GPIO_X15, 1);
+ gpio_cfg_pin(GPIO_X30, GPIO_OUTPUT);
+ gpio_set_value(GPIO_X30, 1);
+}
+
+static void exynos_pinmux_i2c(int start, int func)
+{
+ gpio_cfg_pin(start, GPIO_FUNC(func));
+ gpio_cfg_pin(start + 1, GPIO_FUNC(func));
+ gpio_set_pull(start, GPIO_PULL_NONE);
+ gpio_set_pull(start + 1, GPIO_PULL_NONE);
+}
+
+void exynos_pinmux_i2c0(void)
+{
+ exynos_pinmux_i2c(GPIO_B30, 0x2);
+}
+
+void exynos_pinmux_i2c1(void)
+{
+ exynos_pinmux_i2c(GPIO_B32, 0x2);
+}
+
+void exynos_pinmux_i2c2(void)
+{
+ exynos_pinmux_i2c(GPIO_A06, 0x3);
+}
+
+void exynos_pinmux_i2c3(void)
+{
+ exynos_pinmux_i2c(GPIO_A12, 0x3);
+}
+
+void exynos_pinmux_i2c4(void)
+{
+ exynos_pinmux_i2c(GPIO_A20, 0x3);
+}
+
+void exynos_pinmux_i2c5(void)
+{
+ exynos_pinmux_i2c(GPIO_A22, 0x3);
+}
+
+void exynos_pinmux_i2c6(void)
+{
+ exynos_pinmux_i2c(GPIO_B13, 0x4);
+}
+
+void exynos_pinmux_i2c7(void)
+{
+ exynos_pinmux_i2c(GPIO_B22, 0x3);
+}
+
+void exynos_pinmux_dphpd(void)
+{
+ /* Set Hotplug detect for DP */
+ gpio_cfg_pin(GPIO_X07, GPIO_FUNC(0x3));
+
+ /*
+ * Hotplug detect should have an external pullup; disable the
+ * internal pulldown so they don't fight.
+ */
+ gpio_set_pull(GPIO_X07, GPIO_PULL_NONE);
+}
+
+void exynos_pinmux_i2s0(void)
+{
+ int i;
+
+ for (i = 0; i < 5; i++) {
+ gpio_cfg_pin(GPIO_Z0 + i, GPIO_FUNC(0x02));
+ gpio_set_pull(GPIO_Z0 + i, GPIO_PULL_NONE);
+ }
+}
+
+void exynos_pinmux_i2s1(void)
+{
+ int i;
+
+ for (i = 0; i < 5; i++) {
+ gpio_cfg_pin(GPIO_B00 + i, GPIO_FUNC(0x02));
+ gpio_set_pull(GPIO_B00 + i, GPIO_PULL_NONE);
+ }
+}
diff --git a/src/soc/samsung/exynos5250/pinmux.h b/src/soc/samsung/exynos5250/pinmux.h
new file mode 100644
index 0000000..227a280
--- /dev/null
+++ b/src/soc/samsung/exynos5250/pinmux.h
@@ -0,0 +1,58 @@
+/*
+ * This file is part of the coreboot project.
+ *
+ * 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; 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
+ */
+
+#ifndef CPU_SAMSUNG_EXYNOS5250_PINMUX_H
+#define CPU_SAMSUNG_EXYNOS5250_PINMUX_H
+
+void exynos_pinmux_uart0(void);
+void exynos_pinmux_uart1(void);
+void exynos_pinmux_uart2(void);
+void exynos_pinmux_uart3(void);
+
+void exynos_pinmux_sdmmc0(void);
+void exynos_pinmux_sdmmc1(void);
+void exynos_pinmux_sdmmc2(void);
+void exynos_pinmux_sdmmc3(void);
+
+void exynos_pinmux_sromc(int bank, int sixteen_bit);
+
+void exynos_pinmux_spi0(void);
+void exynos_pinmux_spi1(void);
+void exynos_pinmux_spi2(void);
+void exynos_pinmux_spi3(void);
+void exynos_pinmux_spi4(void);
+
+void exynos_pinmux_backlight(void);
+void exynos_pinmux_lcd(void);
+
+void exynos_pinmux_i2c0(void);
+void exynos_pinmux_i2c1(void);
+void exynos_pinmux_i2c2(void);
+void exynos_pinmux_i2c3(void);
+void exynos_pinmux_i2c4(void);
+void exynos_pinmux_i2c5(void);
+void exynos_pinmux_i2c6(void);
+void exynos_pinmux_i2c7(void);
+
+void exynos_pinmux_dphpd(void);
+
+void exynos_pinmux_i2s0(void);
+void exynos_pinmux_i2s1(void);
+
+#endif
diff --git a/src/soc/samsung/exynos5250/power.c b/src/soc/samsung/exynos5250/power.c
new file mode 100644
index 0000000..c9d620a
--- /dev/null
+++ b/src/soc/samsung/exynos5250/power.c
@@ -0,0 +1,90 @@
+/*
+ * This file is part of the coreboot project.
+ *
+ * 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; 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
+ */
+
+/* Power setup code for EXYNOS5 */
+
+#include <arch/io.h>
+#include <arch/hlt.h>
+#include <console/console.h>
+#include "power.h"
+
+static void ps_hold_setup(void)
+{
+ /* Set PS-Hold high */
+ setbits_le32(&exynos_power->ps_hold_ctrl,
+ POWER_PS_HOLD_CONTROL_DATA_HIGH);
+}
+
+void power_reset(void)
+{
+ /* Clear inform1 so there's no change we think we've got a wake reset */
+ exynos_power->inform1 = 0;
+
+ setbits_le32(&exynos_power->sw_reset, 1);
+}
+
+/* This function never returns */
+void power_shutdown(void)
+{
+ clrbits_le32(&exynos_power->ps_hold_ctrl,
+ POWER_PS_HOLD_CONTROL_DATA_HIGH);
+
+ hlt();
+}
+
+void power_enable_dp_phy(void)
+{
+ setbits_le32(&exynos_power->dptx_phy_control, DPTX_PHY_ENABLE);
+}
+
+void power_enable_hw_thermal_trip(void)
+{
+ /* Enable HW thermal trip */
+ setbits_le32(&exynos_power->ps_hold_ctrl, POWER_ENABLE_HW_TRIP);
+}
+
+uint32_t power_read_reset_status(void)
+{
+ return exynos_power->inform1;
+}
+
+void power_exit_wakeup(void)
+{
+ typedef void (*resume_func)(void);
+
+ ((resume_func)exynos_power->inform0)();
+}
+
+int power_init(void)
+{
+ ps_hold_setup();
+ return 0;
+}
+
+void power_enable_xclkout(void)
+{
+ /* use xxti for xclk out */
+ clrsetbits_le32(&exynos_power->pmu_debug, PMU_DEBUG_CLKOUT_SEL_MASK,
+ PMU_DEBUG_XXTI);
+}
+
+void power_release_uart_retention(void)
+{
+ writel(1 << 28, &exynos_power->padret_uart_opt);
+}
diff --git a/src/soc/samsung/exynos5250/power.h b/src/soc/samsung/exynos5250/power.h
new file mode 100644
index 0000000..5ea73c7
--- /dev/null
+++ b/src/soc/samsung/exynos5250/power.h
@@ -0,0 +1,99 @@
+/*
+ * This file is part of the coreboot project.
+ *
+ * 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; 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
+ */
+
+/* Register map for Exynos5 PMU */
+
+#ifndef CPU_SAMSUNG_EXYNOS5250_POWER_H
+#define CPU_SAMSUNG_EXYNOS5250_POWER_H
+
+#include "cpu.h"
+
+/* Enable HW thermal trip with PS_HOLD_CONTROL register ENABLE_HW_TRIP bit */
+void power_enable_hw_thermal_trip(void);
+
+#define MIPI_PHY1_CONTROL_ENABLE (1 << 0)
+#define MIPI_PHY1_CONTROL_M_RESETN (1 << 2)
+
+#define POWER_USB_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 */
+ uint32_t om_stat; /* 0x0000 */
+ uint8_t reserved1[0x03fc];
+ uint32_t sw_reset; /* 0x0400 */
+ uint8_t reserved2[0x0300];
+ uint32_t usb_drd_phy_ctrl; /* 0x0704 */
+ 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[0x2728];
+ uint32_t padret_uart_opt; /* 0x3128 */
+ uint8_t reserved8[0x1e0];
+ uint32_t ps_hold_ctrl; /* 0x330c */
+} __attribute__ ((__packed__));
+
+static struct exynos5_power * const exynos_power = (void*)EXYNOS5_POWER_BASE;
+
+/**
+ * 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);
+
+/* 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);
+
+/* Release UART retention on resume (only for debugging, may conflict with
+ * kernel). */
+void power_release_uart_retention(void);
+
+#endif
diff --git a/src/soc/samsung/exynos5250/setup.h b/src/soc/samsung/exynos5250/setup.h
new file mode 100644
index 0000000..c65747b
--- /dev/null
+++ b/src/soc/samsung/exynos5250/setup.h
@@ -0,0 +1,755 @@
+/*
+ * This file is part of the coreboot project.
+ *
+ * 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; 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
+ */
+
+/* Machine Specific Values for SMDK5250 board based on Exynos5 */
+
+#ifndef CPU_SAMSUNG_EXYNOS5250_SETUP_H
+#define CPU_SAMSUNG_EXYNOS5250_SETUP_H
+
+struct exynos5_dmc;
+enum ddr_mode;
+struct exynos5_phy_control;
+
+/* TZPC : Register Offsets */
+#define TZPC0_BASE 0x10100000
+#define TZPC1_BASE 0x10110000
+#define TZPC2_BASE 0x10120000
+#define TZPC3_BASE 0x10130000
+#define TZPC4_BASE 0x10140000
+#define TZPC5_BASE 0x10150000
+#define TZPC6_BASE 0x10160000
+#define TZPC7_BASE 0x10170000
+#define TZPC8_BASE 0x10180000
+#define TZPC9_BASE 0x10190000
+
+#define APLL_FOUT (1 << 0)
+
+/* APLL_CON1 */
+#define APLL_CON1_VAL (0x00203800)
+
+/* MPLL_CON1 */
+#define MPLL_CON1_VAL (0x00203800)
+
+/* CPLL_CON1 */
+#define CPLL_CON1_VAL (0x00203800)
+
+/* GPLL_CON1 */
+#define GPLL_CON1_VAL (0x00203800)
+
+/* EPLL_CON1, CON2 */
+#define EPLL_CON1_VAL 0x00000000
+#define EPLL_CON2_VAL 0x00000080
+
+/* VPLL_CON1, CON2 */
+#define VPLL_CON1_VAL 0x00000000
+#define VPLL_CON2_VAL 0x00000080
+
+/* BPLL_CON1 */
+#define BPLL_CON1_VAL 0x00203800
+
+/* Set PLL */
+#define set_pll(mdiv, pdiv, sdiv) (1<<31 | mdiv<<16 | pdiv<<8 | sdiv)
+
+/* CLK_SRC_CPU */
+/* 0 = MOUTAPLL, 1 = SCLKMPLL */
+#define MUX_HPM_SEL 0
+#define MUX_CPU_SEL 0
+#define MUX_APLL_SEL 1
+
+#define CLK_SRC_CPU_VAL ((MUX_HPM_SEL << 20) \
+ | (MUX_CPU_SEL << 16) \
+ | (MUX_APLL_SEL))
+
+/* MEMCONTROL register bit fields */
+#define DMC_MEMCONTROL_CLK_STOP_DISABLE (0 << 0)
+#define DMC_MEMCONTROL_DPWRDN_DISABLE (0 << 1)
+#define DMC_MEMCONTROL_DPWRDN_ACTIVE_PRECHARGE (0 << 2)
+#define DMC_MEMCONTROL_TP_DISABLE (0 << 4)
+#define DMC_MEMCONTROL_DSREF_DISABLE (0 << 5)
+#define DMC_MEMCONTROL_DSREF_ENABLE (1 << 5)
+#define DMC_MEMCONTROL_ADD_LAT_PALL_CYCLE(x) (x << 6)
+
+#define DMC_MEMCONTROL_MEM_TYPE_LPDDR3 (7 << 8)
+#define DMC_MEMCONTROL_MEM_TYPE_DDR3 (6 << 8)
+#define DMC_MEMCONTROL_MEM_TYPE_LPDDR2 (5 << 8)
+
+#define DMC_MEMCONTROL_MEM_WIDTH_32BIT (2 << 12)
+
+#define DMC_MEMCONTROL_NUM_CHIP_1 (0 << 16)
+#define DMC_MEMCONTROL_NUM_CHIP_2 (1 << 16)
+
+#define DMC_MEMCONTROL_BL_8 (3 << 20)
+#define DMC_MEMCONTROL_BL_4 (2 << 20)
+
+#define DMC_MEMCONTROL_PZQ_DISABLE (0 << 24)
+
+#define DMC_MEMCONTROL_MRR_BYTE_7_0 (0 << 25)
+#define DMC_MEMCONTROL_MRR_BYTE_15_8 (1 << 25)
+#define DMC_MEMCONTROL_MRR_BYTE_23_16 (2 << 25)
+#define DMC_MEMCONTROL_MRR_BYTE_31_24 (3 << 25)
+
+/* MEMCONFIG0 register bit fields */
+#define DMC_MEMCONFIGx_CHIP_MAP_INTERLEAVED (1 << 12)
+#define DMC_MEMCONFIGx_CHIP_COL_10 (3 << 8)
+#define DMC_MEMCONFIGx_CHIP_ROW_14 (2 << 4)
+#define DMC_MEMCONFIGx_CHIP_ROW_15 (3 << 4)
+#define DMC_MEMCONFIGx_CHIP_BANK_8 (3 << 0)
+
+#define DMC_MEMBASECONFIGx_CHIP_BASE(x) (x << 16)
+#define DMC_MEMBASECONFIGx_CHIP_MASK(x) (x << 0)
+#define DMC_MEMBASECONFIG_VAL(x) ( \
+ DMC_MEMBASECONFIGx_CHIP_BASE(x) | \
+ DMC_MEMBASECONFIGx_CHIP_MASK(0x780) \
+)
+
+#define DMC_MEMBASECONFIG0_VAL DMC_MEMBASECONFIG_VAL(0x40)
+#define DMC_MEMBASECONFIG1_VAL DMC_MEMBASECONFIG_VAL(0x80)
+
+#define DMC_PRECHCONFIG_VAL 0xFF000000
+#define DMC_PWRDNCONFIG_VAL 0xFFFF00FF
+
+#define DMC_CONCONTROL_RESET_VAL 0x0FFF0000
+#define DFI_INIT_START (1 << 28)
+#define EMPTY (1 << 8)
+#define AREF_EN (1 << 5)
+
+#define DFI_INIT_COMPLETE_CHO (1 << 2)
+#define DFI_INIT_COMPLETE_CH1 (1 << 3)
+
+#define RDLVL_COMPLETE_CHO (1 << 14)
+#define RDLVL_COMPLETE_CH1 (1 << 15)
+
+#define CLK_STOP_EN (1 << 0)
+#define DPWRDN_EN (1 << 1)
+#define DSREF_EN (1 << 5)
+
+/* COJCONTROL register bit fields */
+#define DMC_CONCONTROL_IO_PD_CON_DISABLE (0 << 3)
+#define DMC_CONCONTROL_AREF_EN_DISABLE (0 << 5)
+#define DMC_CONCONTROL_EMPTY_DISABLE (0 << 8)
+#define DMC_CONCONTROL_EMPTY_ENABLE (1 << 8)
+#define DMC_CONCONTROL_RD_FETCH_DISABLE (0x0 << 12)
+#define DMC_CONCONTROL_TIMEOUT_LEVEL0 (0xFFF << 16)
+#define DMC_CONCONTROL_DFI_INIT_START_DISABLE (0 << 28)
+
+/* CLK_DIV_CPU0_VAL */
+#define CLK_DIV_CPU0_VAL ((ARM2_RATIO << 28) \
+ | (APLL_RATIO << 24) \
+ | (PCLK_DBG_RATIO << 20) \
+ | (ATB_RATIO << 16) \
+ | (PERIPH_RATIO << 12) \
+ | (ACP_RATIO << 8) \
+ | (CPUD_RATIO << 4) \
+ | (ARM_RATIO))
+
+
+/* CLK_FSYS */
+#define CLK_SRC_FSYS0_VAL 0x66666
+#define CLK_DIV_FSYS0_VAL 0x0BB00000
+
+/* CLK_DIV_CPU1 */
+#define HPM_RATIO 0x2
+#define COPY_RATIO 0x0
+
+/* CLK_DIV_CPU1 = 0x00000003 */
+#define CLK_DIV_CPU1_VAL ((HPM_RATIO << 4) \
+ | (COPY_RATIO))
+
+/* CLK_SRC_CORE0 */
+#define CLK_SRC_CORE0_VAL 0x00000000
+
+/* CLK_SRC_CORE1 */
+#define CLK_SRC_CORE1_VAL 0x100
+
+/* CLK_DIV_CORE0 */
+#define CLK_DIV_CORE0_VAL 0x00120000
+
+/* CLK_DIV_CORE1 */
+#define CLK_DIV_CORE1_VAL 0x07070700
+
+/* CLK_DIV_SYSRGT */
+#define CLK_DIV_SYSRGT_VAL 0x00000111
+
+/* CLK_DIV_ACP */
+#define CLK_DIV_ACP_VAL 0x12
+
+/* CLK_DIV_SYSLFT */
+#define CLK_DIV_SYSLFT_VAL 0x00000311
+
+/* CLK_SRC_CDREX */
+#define CLK_SRC_CDREX_VAL 0x1
+
+/* CLK_DIV_CDREX */
+#define MCLK_CDREX2_RATIO 0x0
+#define ACLK_EFCON_RATIO 0x1
+#define MCLK_DPHY_RATIO 0x1
+#define MCLK_CDREX_RATIO 0x1
+#define ACLK_C2C_200_RATIO 0x1
+#define C2C_CLK_400_RATIO 0x1
+#define PCLK_CDREX_RATIO 0x1
+#define ACLK_CDREX_RATIO 0x1
+
+#define CLK_DIV_CDREX_VAL ((MCLK_DPHY_RATIO << 24) \
+ | (C2C_CLK_400_RATIO << 6) \
+ | (PCLK_CDREX_RATIO << 4) \
+ | (ACLK_CDREX_RATIO))
+
+/* CLK_SRC_TOP0 */
+#define MUX_ACLK_300_GSCL_SEL 0x0
+#define MUX_ACLK_300_GSCL_MID_SEL 0x0
+#define MUX_ACLK_400_G3D_MID_SEL 0x0
+#define MUX_ACLK_333_SEL 0x0
+#define MUX_ACLK_300_DISP1_SEL 0x0
+#define MUX_ACLK_300_DISP1_MID_SEL 0x0
+#define MUX_ACLK_200_SEL 0x0
+#define MUX_ACLK_166_SEL 0x0
+#define CLK_SRC_TOP0_VAL ((MUX_ACLK_300_GSCL_SEL << 25) \
+ | (MUX_ACLK_300_GSCL_MID_SEL << 24) \
+ | (MUX_ACLK_400_G3D_MID_SEL << 20) \
+ | (MUX_ACLK_333_SEL << 16) \
+ | (MUX_ACLK_300_DISP1_SEL << 15) \
+ | (MUX_ACLK_300_DISP1_MID_SEL << 14) \
+ | (MUX_ACLK_200_SEL << 12) \
+ | (MUX_ACLK_166_SEL << 8))
+
+/* CLK_SRC_TOP1 */
+#define MUX_ACLK_400_G3D_SEL 0x1
+#define MUX_ACLK_400_ISP_SEL 0x0
+#define MUX_ACLK_400_IOP_SEL 0x0
+#define MUX_ACLK_MIPI_HSI_TXBASE_SEL 0x0
+#define MUX_ACLK_300_GSCL_MID1_SEL 0x0
+#define MUX_ACLK_300_DISP1_MID1_SEL 0x0
+#define CLK_SRC_TOP1_VAL ((MUX_ACLK_400_G3D_SEL << 28) \
+ |(MUX_ACLK_400_ISP_SEL << 24) \
+ |(MUX_ACLK_400_IOP_SEL << 20) \
+ |(MUX_ACLK_MIPI_HSI_TXBASE_SEL << 16) \
+ |(MUX_ACLK_300_GSCL_MID1_SEL << 12) \
+ |(MUX_ACLK_300_DISP1_MID1_SEL << 8))
+
+/* CLK_SRC_TOP2 */
+#define MUX_GPLL_SEL 0x1
+#define MUX_BPLL_USER_SEL 0x0
+#define MUX_MPLL_USER_SEL 0x0
+#define MUX_VPLL_SEL 0x1
+#define MUX_EPLL_SEL 0x1
+#define MUX_CPLL_SEL 0x1
+#define VPLLSRC_SEL 0x0
+#define CLK_SRC_TOP2_VAL ((MUX_GPLL_SEL << 28) \
+ | (MUX_BPLL_USER_SEL << 24) \
+ | (MUX_MPLL_USER_SEL << 20) \
+ | (MUX_VPLL_SEL << 16) \
+ | (MUX_EPLL_SEL << 12) \
+ | (MUX_CPLL_SEL << 8) \
+ | (VPLLSRC_SEL))
+/* CLK_SRC_TOP3 */
+#define MUX_ACLK_333_SUB_SEL 0x1
+#define MUX_ACLK_400_SUB_SEL 0x1
+#define MUX_ACLK_266_ISP_SUB_SEL 0x1
+#define MUX_ACLK_266_GPS_SUB_SEL 0x0
+#define MUX_ACLK_300_GSCL_SUB_SEL 0x1
+#define MUX_ACLK_266_GSCL_SUB_SEL 0x1
+#define MUX_ACLK_300_DISP1_SUB_SEL 0x1
+#define MUX_ACLK_200_DISP1_SUB_SEL 0x1
+#define CLK_SRC_TOP3_VAL ((MUX_ACLK_333_SUB_SEL << 24) \
+ | (MUX_ACLK_400_SUB_SEL << 20) \
+ | (MUX_ACLK_266_ISP_SUB_SEL << 16) \
+ | (MUX_ACLK_266_GPS_SUB_SEL << 12) \
+ | (MUX_ACLK_300_GSCL_SUB_SEL << 10) \
+ | (MUX_ACLK_266_GSCL_SUB_SEL << 8) \
+ | (MUX_ACLK_300_DISP1_SUB_SEL << 6) \
+ | (MUX_ACLK_200_DISP1_SUB_SEL << 4))
+
+/* CLK_DIV_TOP0 */
+#define ACLK_300_DISP1_RATIO 0x2
+#define ACLK_400_G3D_RATIO 0x0
+#define ACLK_333_RATIO 0x0
+#define ACLK_266_RATIO 0x2
+#define ACLK_200_RATIO 0x3
+#define ACLK_166_RATIO 0x1
+#define ACLK_133_RATIO 0x1
+#define ACLK_66_RATIO 0x5
+
+#define CLK_DIV_TOP0_VAL ((ACLK_300_DISP1_RATIO << 28) \
+ | (ACLK_400_G3D_RATIO << 24) \
+ | (ACLK_333_RATIO << 20) \
+ | (ACLK_266_RATIO << 16) \
+ | (ACLK_200_RATIO << 12) \
+ | (ACLK_166_RATIO << 8) \
+ | (ACLK_133_RATIO << 4) \
+ | (ACLK_66_RATIO))
+
+/* CLK_DIV_TOP1 */
+#define ACLK_MIPI_HSI_TX_BASE_RATIO 0x3
+#define ACLK_66_PRE_RATIO 0x1
+#define ACLK_400_ISP_RATIO 0x1
+#define ACLK_400_IOP_RATIO 0x1
+#define ACLK_300_GSCL_RATIO 0x2
+
+#define CLK_DIV_TOP1_VAL ((ACLK_MIPI_HSI_TX_BASE_RATIO << 28) \
+ | (ACLK_66_PRE_RATIO << 24) \
+ | (ACLK_400_ISP_RATIO << 20) \
+ | (ACLK_400_IOP_RATIO << 16) \
+ | (ACLK_300_GSCL_RATIO << 12))
+
+/* APLL_LOCK */
+#define APLL_LOCK_VAL (0x546)
+/* MPLL_LOCK */
+#define MPLL_LOCK_VAL (0x546)
+/* CPLL_LOCK */
+#define CPLL_LOCK_VAL (0x546)
+/* GPLL_LOCK */
+#define GPLL_LOCK_VAL (0x546)
+/* EPLL_LOCK */
+#define EPLL_LOCK_VAL (0x3A98)
+/* VPLL_LOCK */
+#define VPLL_LOCK_VAL (0x3A98)
+/* BPLL_LOCK */
+#define BPLL_LOCK_VAL (0x546)
+
+#define MUX_MCLK_CDREX_SEL (1 << 4)
+#define MUX_MCLK_DPHY_SEL (1 << 8)
+
+#define MUX_APLL_SEL_MASK (1 << 0)
+#define MUX_MPLL_FOUT_SEL (1 << 4)
+#define MUX_BPLL_FOUT_SEL (1 << 0)
+#define MUX_MPLL_SEL_MASK (1 << 8)
+#define MPLL_SEL_MOUT_MPLLFOUT (2 << 8)
+#define MUX_CPLL_SEL_MASK (1 << 8)
+#define MUX_EPLL_SEL_MASK (1 << 12)
+#define MUX_VPLL_SEL_MASK (1 << 16)
+#define MUX_GPLL_SEL_MASK (1 << 28)
+#define MUX_BPLL_SEL_MASK (1 << 0)
+#define MUX_HPM_SEL_MASK (1 << 20)
+#define HPM_SEL_SCLK_MPLL (1 << 21)
+#define APLL_CON0_LOCKED (1 << 29)
+#define MPLL_CON0_LOCKED (1 << 29)
+#define BPLL_CON0_LOCKED (1 << 29)
+#define CPLL_CON0_LOCKED (1 << 29)
+#define EPLL_CON0_LOCKED (1 << 29)
+#define GPLL_CON0_LOCKED (1 << 29)
+#define VPLL_CON0_LOCKED (1 << 29)
+#define CLK_REG_DISABLE 0x0
+#define TOP2_VAL 0x0110000
+
+/* CLK_SRC_PERIC0 */
+#define PWM_SEL 6
+#define UART3_SEL 6
+#define UART2_SEL 6
+#define UART1_SEL 6
+#define UART0_SEL 6
+/* SRC_CLOCK = SCLK_MPLL */
+#define CLK_SRC_PERIC0_VAL ((PWM_SEL << 24) \
+ | (UART3_SEL << 12) \
+ | (UART2_SEL << 8) \
+ | (UART1_SEL << 4) \
+ | (UART0_SEL))
+
+/* CLK_SRC_PERIC1 */
+/* SRC_CLOCK = SCLK_MPLL */
+#define SPI0_SEL 6
+#define SPI1_SEL 6
+#define SPI2_SEL 6
+#define CLK_SRC_PERIC1_VAL ((SPI2_SEL << 24) \
+ | (SPI1_SEL << 20) \
+ | (SPI0_SEL << 16))
+
+/* SCLK_SRC_ISP - set SPI0/1 to 6 = SCLK_MPLL_USER */
+#define SPI0_ISP_SEL 6
+#define SPI1_ISP_SEL 6
+#define SCLK_SRC_ISP_VAL (SPI1_ISP_SEL << 4) \
+ | (SPI0_ISP_SEL << 0)
+
+/* SCLK_DIV_ISP - set SPI0/1 to 0xf = divide by 16 */
+#define SPI0_ISP_RATIO 0xf
+#define SPI1_ISP_RATIO 0xf
+#define SCLK_DIV_ISP_VAL (SPI1_ISP_RATIO << 12) \
+ | (SPI0_ISP_RATIO << 0)
+
+/* CLK_DIV_PERIL0 */
+#define UART5_RATIO 7
+#define UART4_RATIO 7
+#define UART3_RATIO 7
+#define UART2_RATIO 7
+#define UART1_RATIO 7
+#define UART0_RATIO 7
+
+#define CLK_DIV_PERIC0_VAL ((UART3_RATIO << 12) \
+ | (UART2_RATIO << 8) \
+ | (UART1_RATIO << 4) \
+ | (UART0_RATIO))
+/* CLK_DIV_PERIC1 */
+#define SPI1_RATIO 0x7
+#define SPI0_RATIO 0xf
+#define SPI1_SUB_RATIO 0x0
+#define SPI0_SUB_RATIO 0x0
+#define CLK_DIV_PERIC1_VAL ((SPI1_SUB_RATIO << 24) \
+ | ((SPI1_RATIO << 16) \
+ | (SPI0_SUB_RATIO << 8) \
+ | (SPI0_RATIO << 0)))
+
+/* CLK_DIV_PERIC2 */
+#define SPI2_RATIO 0xf
+#define SPI2_SUB_RATIO 0x0
+#define CLK_DIV_PERIC2_VAL ((SPI2_SUB_RATIO << 8) \
+ | (SPI2_RATIO << 0))
+/* CLK_DIV_FSYS2 */
+#define MMC2_RATIO_MASK 0xf
+#define MMC2_RATIO_VAL 0x3
+#define MMC2_RATIO_OFFSET 0
+
+#define MMC2_PRE_RATIO_MASK 0xff
+#define MMC2_PRE_RATIO_VAL 0x9
+#define MMC2_PRE_RATIO_OFFSET 8
+
+#define MMC3_RATIO_MASK 0xf
+#define MMC3_RATIO_VAL 0x1
+#define MMC3_RATIO_OFFSET 16
+
+#define MMC3_PRE_RATIO_MASK 0xff
+#define MMC3_PRE_RATIO_VAL 0x0
+#define MMC3_PRE_RATIO_OFFSET 24
+
+/* CLK_SRC_LEX */
+#define CLK_SRC_LEX_VAL 0x0
+
+/* CLK_DIV_LEX */
+#define CLK_DIV_LEX_VAL 0x10
+
+/* CLK_DIV_R0X */
+#define CLK_DIV_R0X_VAL 0x10
+
+/* CLK_DIV_L0X */
+#define CLK_DIV_R1X_VAL 0x10
+
+/* CLK_DIV_ISP0 */
+#define CLK_DIV_ISP0_VAL 0x31
+
+/* CLK_DIV_ISP1 */
+#define CLK_DIV_ISP1_VAL 0x0
+
+/* CLK_DIV_ISP2 */
+#define CLK_DIV_ISP2_VAL 0x1
+
+/* CLK_SRC_DISP1_0 */
+#define CLK_SRC_DISP1_0_VAL 0x6
+
+/*
+ * DIV_DISP1_0
+ * For DP, divisor should be 2
+ */
+#define CLK_DIV_DISP1_0_FIMD1 (2 << 0)
+
+/* CLK_GATE_IP_DISP1 */
+#define CLK_GATE_DP1_ALLOW (1 << 4)
+
+/* CLK_GATE_IP_SYSRGT */
+#define CLK_C2C_MASK (1 << 1)
+
+/* CLK_GATE_IP_ACP */
+#define CLK_SMMUG2D_MASK (1 << 7)
+#define CLK_SMMUSSS_MASK (1 << 6)
+#define CLK_SMMUMDMA_MASK (1 << 5)
+#define CLK_ID_REMAPPER_MASK (1 << 4)
+#define CLK_G2D_MASK (1 << 3)
+#define CLK_SSS_MASK (1 << 2)
+#define CLK_MDMA_MASK (1 << 1)
+#define CLK_SECJTAG_MASK (1 << 0)
+
+/* CLK_GATE_BUS_SYSLFT */
+#define CLK_EFCLK_MASK (1 << 16)
+
+/* CLK_GATE_IP_ISP0 */
+#define CLK_UART_ISP_MASK (1 << 31)
+#define CLK_WDT_ISP_MASK (1 << 30)
+#define CLK_PWM_ISP_MASK (1 << 28)
+#define CLK_MTCADC_ISP_MASK (1 << 27)
+#define CLK_I2C1_ISP_MASK (1 << 26)
+#define CLK_I2C0_ISP_MASK (1 << 25)
+#define CLK_MPWM_ISP_MASK (1 << 24)
+#define CLK_MCUCTL_ISP_MASK (1 << 23)
+#define CLK_INT_COMB_ISP_MASK (1 << 22)
+#define CLK_SMMU_MCUISP_MASK (1 << 13)
+#define CLK_SMMU_SCALERP_MASK (1 << 12)
+#define CLK_SMMU_SCALERC_MASK (1 << 11)
+#define CLK_SMMU_FD_MASK (1 << 10)
+#define CLK_SMMU_DRC_MASK (1 << 9)
+#define CLK_SMMU_ISP_MASK (1 << 8)
+#define CLK_GICISP_MASK (1 << 7)
+#define CLK_ARM9S_MASK (1 << 6)
+#define CLK_MCUISP_MASK (1 << 5)
+#define CLK_SCALERP_MASK (1 << 4)
+#define CLK_SCALERC_MASK (1 << 3)
+#define CLK_FD_MASK (1 << 2)
+#define CLK_DRC_MASK (1 << 1)
+#define CLK_ISP_MASK (1 << 0)
+
+/* CLK_GATE_IP_ISP1 */
+#define CLK_SPI1_ISP_MASK (1 << 13)
+#define CLK_SPI0_ISP_MASK (1 << 12)
+#define CLK_SMMU3DNR_MASK (1 << 7)
+#define CLK_SMMUDIS1_MASK (1 << 6)
+#define CLK_SMMUDIS0_MASK (1 << 5)
+#define CLK_SMMUODC_MASK (1 << 4)
+#define CLK_3DNR_MASK (1 << 2)
+#define CLK_DIS_MASK (1 << 1)
+#define CLK_ODC_MASK (1 << 0)
+
+/* CLK_GATE_IP_GSCL */
+#define CLK_SMMUFIMC_LITE2_MASK (1 << 20)
+#define CLK_SMMUFIMC_LITE1_MASK (1 << 12)
+#define CLK_SMMUFIMC_LITE0_MASK (1 << 11)
+#define CLK_SMMUGSCL3_MASK (1 << 10)
+#define CLK_SMMUGSCL2_MASK (1 << 9)
+#define CLK_SMMUGSCL1_MASK (1 << 8)
+#define CLK_SMMUGSCL0_MASK (1 << 7)
+#define CLK_GSCL_WRAP_B_MASK (1 << 6)
+#define CLK_GSCL_WRAP_A_MASK (1 << 5)
+#define CLK_CAMIF_TOP_MASK (1 << 4)
+#define CLK_GSCL3_MASK (1 << 3)
+#define CLK_GSCL2_MASK (1 << 2)
+#define CLK_GSCL1_MASK (1 << 1)
+#define CLK_GSCL0_MASK (1 << 0)
+
+/* CLK_GATE_IP_MFC */
+#define CLK_SMMUMFCR_MASK (1 << 2)
+#define CLK_SMMUMFCL_MASK (1 << 1)
+#define CLK_MFC_MASK (1 << 0)
+
+#define SCLK_MPWM_ISP_MASK (1 << 0)
+
+/* CLK_GATE_IP_DISP1 */
+#define CLK_SMMUTVX_MASK (1 << 9)
+#define CLK_ASYNCTVX_MASK (1 << 7)
+#define CLK_HDMI_MASK (1 << 6)
+#define CLK_MIXER_MASK (1 << 5)
+#define CLK_DSIM1_MASK (1 << 3)
+
+/* CLK_GATE_IP_GEN */
+#define CLK_SMMUMDMA1_MASK (1 << 9)
+#define CLK_SMMUJPEG_MASK (1 << 7)
+#define CLK_SMMUROTATOR_MASK (1 << 6)
+#define CLK_MDMA1_MASK (1 << 4)
+#define CLK_JPEG_MASK (1 << 2)
+#define CLK_ROTATOR_MASK (1 << 1)
+
+/* CLK_GATE_IP_FSYS */
+#define CLK_WDT_IOP_MASK (1 << 30)
+#define CLK_SMMUMCU_IOP_MASK (1 << 26)
+#define CLK_SATA_PHY_I2C_MASK (1 << 25)
+#define CLK_SATA_PHY_CTRL_MASK (1 << 24)
+#define CLK_MCUCTL_MASK (1 << 23)
+#define CLK_NFCON_MASK (1 << 22)
+#define CLK_SMMURTIC_MASK (1 << 11)
+#define CLK_RTIC_MASK (1 << 9)
+#define CLK_MIPI_HSI_MASK (1 << 8)
+#define CLK_USBOTG_MASK (1 << 7)
+#define CLK_SATA_MASK (1 << 6)
+#define CLK_PDMA1_MASK (1 << 2)
+#define CLK_PDMA0_MASK (1 << 1)
+#define CLK_MCU_IOP_MASK (1 << 0)
+
+/* CLK_GATE_IP_PERIC */
+#define CLK_HS_I2C3_MASK (1 << 31)
+#define CLK_HS_I2C2_MASK (1 << 30)
+#define CLK_HS_I2C1_MASK (1 << 29)
+#define CLK_HS_I2C0_MASK (1 << 28)
+#define CLK_AC97_MASK (1 << 27)
+#define CLK_SPDIF_MASK (1 << 26)
+#define CLK_PCM2_MASK (1 << 23)
+#define CLK_PCM1_MASK (1 << 22)
+#define CLK_I2S2_MASK (1 << 21)
+#define CLK_I2S1_MASK (1 << 20)
+#define CLK_SPI2_MASK (1 << 18)
+#define CLK_SPI0_MASK (1 << 16)
+#define CLK_I2CHDMI_MASK (1 << 14)
+#define CLK_I2C7_MASK (1 << 13)
+#define CLK_I2C6_MASK (1 << 12)
+#define CLK_I2C5_MASK (1 << 11)
+#define CLK_I2C4_MASK (1 << 10)
+#define CLK_I2C3_MASK (1 << 9)
+#define CLK_I2C2_MASK (1 << 8)
+#define CLK_I2C1_MASK (1 << 7)
+#define CLK_I2C0_MASK (1 << 6)
+
+/* CLK_GATE_IP_PERIS */
+#define CLK_RTC_MASK (1 << 20)
+#define CLK_TZPC9_MASK (1 << 15)
+#define CLK_TZPC8_MASK (1 << 14)
+#define CLK_TZPC7_MASK (1 << 13)
+#define CLK_TZPC6_MASK (1 << 12)
+#define CLK_TZPC5_MASK (1 << 11)
+#define CLK_TZPC4_MASK (1 << 10)
+#define CLK_TZPC3_MASK (1 << 9)
+#define CLK_TZPC2_MASK (1 << 8)
+#define CLK_TZPC1_MASK (1 << 7)
+#define CLK_TZPC0_MASK (1 << 6)
+#define CLK_CHIPID_MASK (1 << 0)
+
+/* CLK_GATE_BLOCK */
+#define CLK_ACP_MASK (1 << 7)
+
+/* CLK_GATE_IP_CDREX */
+#define CLK_TZASC_DRBXW_MASK (1 << 23)
+#define CLK_TZASC_DRBXR_MASK (1 << 22)
+#define CLK_TZASC_XLBXW_MASK (1 << 21)
+#define CLK_TZASC_XLBXR_MASK (1 << 20)
+#define CLK_TZASC_XR1BXW_MASK (1 << 19)
+#define CLK_TZASC_XR1BXR_MASK (1 << 18)
+#define CLK_DPHY1_MASK (1 << 5)
+#define CLK_DPHY0_MASK (1 << 4)
+
+/*
+ * TZPC Register Value :
+ * R0SIZE: 0x0 : Size of secured ram
+ */
+#define R0SIZE 0x0
+
+/*
+ * TZPC Decode Protection Register Value :
+ * DECPROTXSET: 0xFF : Set Decode region to non-secure
+ */
+#define DECPROTXSET 0xFF
+
+#define LPDDR3PHY_CTRL_PHY_RESET_DISABLE (1 << 0)
+#define LPDDR3PHY_CTRL_PHY_RESET_ENABLE (0 << 0 )
+
+#define PHY_CON0_RESET_VAL 0x17020a40
+#define P0_CMD_EN (1 << 14)
+#define BYTE_RDLVL_EN (1 << 13)
+#define CTRL_SHGATE (1 << 8)
+
+#define PHY_CON1_RESET_VAL 0x09210100
+#define CTRL_GATEDURADJ_MASK (0xf << 20)
+
+#define PHY_CON2_RESET_VAL 0x00010004
+#define INIT_DESKEW_EN (1 << 6)
+#define RDLVL_GATE_EN (1 << 24)
+
+/*ZQ Configurations */
+#define PHY_CON16_RESET_VAL 0x08000304
+
+#define ZQ_CLK_DIV_EN (1 << 18)
+#define ZQ_MANUAL_STR (1 << 1)
+#define ZQ_DONE (1 << 0)
+
+#define CTRL_RDLVL_GATE_ENABLE 1
+#define CTRL_RDLVL_GATE_DISABLE 1
+
+/* Direct Command */
+#define DIRECT_CMD_NOP 0x07000000
+#define DIRECT_CMD_PALL 0x01000000
+#define DIRECT_CMD_ZQINIT 0x0a000000
+#define DIRECT_CMD_CHANNEL_SHIFT 28
+#define DIRECT_CMD_CHIP_SHIFT 20
+
+/* DMC PHY Control0 register */
+#define PHY_CONTROL0_RESET_VAL 0x0
+#define MEM_TERM_EN (1 << 31) /* Termination enable for memory */
+#define PHY_TERM_EN (1 << 30) /* Termination enable for PHY */
+#define DMC_CTRL_SHGATE (1 << 29) /* Duration of DQS gating signal */
+#define FP_RSYNC (1 << 3) /* Force DLL resynchronization */
+
+/* Driver strength for CK, CKE, CS & CA */
+#define IMP_OUTPUT_DRV_40_OHM 0x5
+#define IMP_OUTPUT_DRV_30_OHM 0x7
+#define CA_CK_DRVR_DS_OFFSET 9
+#define CA_CKE_DRVR_DS_OFFSET 6
+#define CA_CS_DRVR_DS_OFFSET 3
+#define CA_ADR_DRVR_DS_OFFSET 0
+
+#define PHY_CON42_CTRL_BSTLEN_SHIFT 8
+#define PHY_CON42_CTRL_RDLAT_SHIFT 0
+
+struct mem_timings;
+
+/* Errors that we can encounter in low-level setup */
+enum {
+ SETUP_ERR_OK,
+ SETUP_ERR_RDLV_COMPLETE_TIMEOUT = -1,
+ SETUP_ERR_ZQ_CALIBRATION_FAILURE = -2,
+};
+
+/* Functions common between LPDDR2 and DDR3 */
+
+/* CPU info initialization code */
+void cpu_info_init(void);
+
+void mem_ctrl_init(void);
+/*
+ * Memory variant specific initialization code
+ *
+ * @param mem Memory timings for this memory type.
+ * @param mem_iv_size Memory interleaving size is a configurable parameter
+ * which the DMC uses to decide how to split a memory
+ * chunk into smaller chunks to support concurrent
+ * accesses; may vary across boards.
+ * @param mem_reset Reset memory during initialization.
+ * @return 0 if ok, SETUP_ERR_... if there is a problem
+ */
+int ddr3_mem_ctrl_init(struct mem_timings *mem, unsigned long mem_iv_size,
+ int mem_reset);
+
+/*
+ * Configure ZQ I/O interface
+ *
+ * @param mem Memory timings for this memory type.
+ * @param phy0_ctrl Pointer to struct containing PHY0 control reg
+ * @param phy1_ctrl Pointer to struct containing PHY1 control reg
+ * @return 0 if ok, -1 on error
+ */
+int dmc_config_zq(struct mem_timings *mem,
+ struct exynos5_phy_control *phy0_ctrl,
+ struct exynos5_phy_control *phy1_ctrl);
+
+/*
+ * Send NOP and MRS/EMRS Direct commands
+ *
+ * @param mem Memory timings for this memory type.
+ * @param dmc Pointer to struct of DMC registers
+ */
+void dmc_config_mrs(struct mem_timings *mem, struct exynos5_dmc *dmc);
+
+/*
+ * Send PALL Direct commands
+ *
+ * @param mem Memory timings for this memory type.
+ * @param dmc Pointer to struct of DMC registers
+ */
+void dmc_config_prech(struct mem_timings *mem, struct exynos5_dmc *dmc);
+
+/*
+ * Configure the memconfig and membaseconfig registers
+ *
+ * @param mem Memory timings for this memory type.
+ * @param exynos5_dmc Pointer to struct of DMC registers
+ */
+void dmc_config_memory(struct mem_timings *mem, struct exynos5_dmc *dmc);
+
+/* Set the PS-Hold drive value */
+void ps_hold_setup(void);
+/*
+ * Reset the DLL. This function is common between DDR3 and LPDDR2.
+ * However, the reset value is different. So we are passing a flag
+ * ddr_mode to distinguish between LPDDR2 and DDR3.
+ *
+ * @param exynos5_dmc Pointer to struct of DMC registers
+ * @param ddr_mode Type of DDR memory
+ */
+void update_reset_dll(struct exynos5_dmc *, enum ddr_mode);
+#endif
diff --git a/src/soc/samsung/exynos5250/spi.c b/src/soc/samsung/exynos5250/spi.c
new file mode 100644
index 0000000..33ec698
--- /dev/null
+++ b/src/soc/samsung/exynos5250/spi.c
@@ -0,0 +1,213 @@
+/*
+ * This file is part of the coreboot project.
+ *
+ * Copyright (C) 2011 Samsung Electronics
+ * Copyright 2013 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 <assert.h>
+#include <stdlib.h>
+#include <arch/io.h>
+#include <console/console.h>
+#include "clk.h"
+#include "gpio.h"
+#include "spi.h"
+
+#if defined(CONFIG_DEBUG_SPI) && CONFIG_DEBUG_SPI
+# define DEBUG_SPI(x,...) printk(BIOS_DEBUG, "EXYNOS_SPI: " x)
+#else
+# define DEBUG_SPI(x,...)
+#endif
+
+static void exynos_spi_rx_tx(struct exynos_spi *regs, int todo,
+ void *dinp, void const *doutp, int i)
+{
+ int rx_lvl, tx_lvl;
+ unsigned int *rxp = (unsigned int *)(dinp + (i * (32 * 1024)));
+ unsigned int out_bytes, in_bytes;
+
+ // TODO In current implementation, every read/write must be aligned to
+ // 4 bytes, otherwise you may get timeout or other unexpected results.
+ ASSERT(todo % 4 == 0);
+
+ 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) {
+ // TODO The "writing" (tx) is not supported now; that's
+ // why we write garbage to keep driving FIFO clock.
+ 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;
+ }
+ }
+}
+
+/* set up SPI channel */
+int exynos_spi_open(struct exynos_spi *regs)
+{
+ /* set the spi1 GPIO */
+
+ /* 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 previously */
+ 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);
+ return 0;
+}
+
+int exynos_spi_read(struct exynos_spi *regs, void *dest, u32 len, u32 off)
+{
+ int upto, todo;
+ int i;
+ 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) | off, ®s->tx_data);
+
+ /* waiting for TX done */
+ while (!(readl(®s->spi_sts) & SPI_ST_TX_DONE));
+
+ for (upto = 0, i = 0; upto < len; upto += todo, i++) {
+ todo = MIN(len - upto, (1 << 15));
+ exynos_spi_rx_tx(regs, todo, dest, (void *)(off), i);
+ }
+
+ setbits_le32(®s->cs_reg, SPI_SLAVE_SIG_INACT);/* make the CS high */
+
+ return len;
+}
+
+int exynos_spi_close(struct exynos_spi *regs)
+{
+ /*
+ * 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);
+ return 0;
+}
+
+// SPI as CBFS media.
+struct exynos_spi_media {
+ struct exynos_spi *regs;
+ struct cbfs_simple_buffer buffer;
+};
+
+static int exynos_spi_cbfs_open(struct cbfs_media *media) {
+ struct exynos_spi_media *spi = (struct exynos_spi_media*)media->context;
+ DEBUG_SPI("exynos_spi_cbfs_open\n");
+ return exynos_spi_open(spi->regs);
+}
+
+static int exynos_spi_cbfs_close(struct cbfs_media *media) {
+ struct exynos_spi_media *spi = (struct exynos_spi_media*)media->context;
+ DEBUG_SPI("exynos_spi_cbfs_close\n");
+ return exynos_spi_close(spi->regs);
+}
+
+static size_t exynos_spi_cbfs_read(struct cbfs_media *media, void *dest,
+ size_t offset, size_t count) {
+ struct exynos_spi_media *spi = (struct exynos_spi_media*)media->context;
+ int bytes;
+ DEBUG_SPI("exynos_spi_cbfs_read(%u)\n", count);
+ bytes = exynos_spi_read(spi->regs, dest, count, offset);
+ // Flush and re-open the device.
+ exynos_spi_close(spi->regs);
+ exynos_spi_open(spi->regs);
+ return bytes;
+}
+
+static void *exynos_spi_cbfs_map(struct cbfs_media *media, size_t offset,
+ size_t count) {
+ struct exynos_spi_media *spi = (struct exynos_spi_media*)media->context;
+ DEBUG_SPI("exynos_spi_cbfs_map\n");
+ // See exynos_spi_rx_tx for I/O alignment limitation.
+ if (count % 4)
+ count += 4 - (count % 4);
+ return cbfs_simple_buffer_map(&spi->buffer, media, offset, count);
+}
+
+static void *exynos_spi_cbfs_unmap(struct cbfs_media *media,
+ const void *address) {
+ struct exynos_spi_media *spi = (struct exynos_spi_media*)media->context;
+ DEBUG_SPI("exynos_spi_cbfs_unmap\n");
+ return cbfs_simple_buffer_unmap(&spi->buffer, address);
+}
+
+int initialize_exynos_spi_cbfs_media(struct cbfs_media *media,
+ void *buffer_address,
+ size_t buffer_size) {
+ // TODO Replace static variable to support multiple streams.
+ static struct exynos_spi_media context;
+ DEBUG_SPI("initialize_exynos_spi_cbfs_media\n");
+
+ context.regs = (void*)EXYNOS5_SPI1_BASE;
+ context.buffer.allocated = context.buffer.last_allocate = 0;
+ context.buffer.buffer = buffer_address;
+ context.buffer.size = buffer_size;
+ media->context = (void*)&context;
+ media->open = exynos_spi_cbfs_open;
+ media->close = exynos_spi_cbfs_close;
+ media->read = exynos_spi_cbfs_read;
+ media->map = exynos_spi_cbfs_map;
+ media->unmap = exynos_spi_cbfs_unmap;
+
+ return 0;
+}
diff --git a/src/soc/samsung/exynos5250/spi.h b/src/soc/samsung/exynos5250/spi.h
new file mode 100644
index 0000000..7ca3114
--- /dev/null
+++ b/src/soc/samsung/exynos5250/spi.h
@@ -0,0 +1,98 @@
+/*
+ * This file is part of the coreboot project.
+ *
+ * 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; 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
+ */
+
+#ifndef CPU_SAMSUNG_EXYNOS5250_SPI_H
+#define CPU_SAMSUNG_EXYNOS5250_SPI_H
+
+/* This driver serves as a CBFS media source. */
+#include <cbfs.h>
+
+/* 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)
+
+/* API */
+int exynos_spi_open(struct exynos_spi *regs);
+int exynos_spi_read(struct exynos_spi *regs, void *dest, u32 len, u32 off);
+int exynos_spi_close(struct exynos_spi *regs);
+
+/* Serve as CBFS media source */
+int initialize_exynos_spi_cbfs_media(struct cbfs_media *media,
+ void *buffer_address,
+ size_t buffer_size);
+#endif
diff --git a/src/soc/samsung/exynos5250/sysreg.h b/src/soc/samsung/exynos5250/sysreg.h
new file mode 100644
index 0000000..1362177
--- /dev/null
+++ b/src/soc/samsung/exynos5250/sysreg.h
@@ -0,0 +1,42 @@
+/*
+ * This file is part of the coreboot project.
+ *
+ * Copyright (c) 2012 Samsung Electronics Co., Ltd.
+ *
+ * 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
+ */
+
+/* Register map for Exynos5 sysreg */
+
+#ifndef CPU_SAMSUNG_EXYNOS5250_SYSREG_H
+#define CPU_SAMSUNG_EXYNOS5250_SYSREG_H
+
+#include "cpu.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;
+};
+
+static struct exynos5_sysreg * const exynos_sysreg =
+ (void *)EXYNOS5_SYSREG_BASE;
+
+#define FIMDBYPASS_DISP1 (1 << 15)
+#define USB20_PHY_CFG_EN (1 << 0)
+
+#endif
diff --git a/src/soc/samsung/exynos5250/timer.c b/src/soc/samsung/exynos5250/timer.c
new file mode 100644
index 0000000..5d402bc
--- /dev/null
+++ b/src/soc/samsung/exynos5250/timer.c
@@ -0,0 +1,53 @@
+/*
+ * This file is part of the coreboot project.
+ *
+ * Copyright (C) 2009 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; 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 <timer.h>
+#include <delay.h>
+
+#include "clk.h"
+
+void init_timer(void)
+{
+ /* Nothing to do because we manually
+ * call mct_start() in the bootblock
+ */
+}
+
+/* delay x useconds */
+void udelay(unsigned usec)
+{
+ struct mono_time current, end;
+
+ timer_monotonic_get(¤t);
+ end = current;
+ mono_time_add_usecs(&end, usec);
+
+ if (mono_time_after(¤t, &end)) {
+ printk(BIOS_EMERG, "udelay: 0x%08x is impossibly large\n",
+ usec);
+ /* There's not much we can do if usec is too big. Use a long,
+ * paranoid delay value and hope for the best... */
+ end = current;
+ mono_time_add_usecs(&end, USECS_PER_SEC);
+ }
+
+ while (mono_time_before(¤t, &end))
+ timer_monotonic_get(¤t);
+}
diff --git a/src/soc/samsung/exynos5250/tmu.c b/src/soc/samsung/exynos5250/tmu.c
new file mode 100644
index 0000000..1b5e9c2
--- /dev/null
+++ b/src/soc/samsung/exynos5250/tmu.c
@@ -0,0 +1,215 @@
+/*
+ * This file is part of the coreboot project.
+ *
+ * Copyright (C) 2012 Samsung Electronics
+ * Copyright 2013 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
+ */
+
+/* EXYNOS - Thermal Management Unit */
+
+#include <console/console.h>
+#include <arch/io.h>
+#include "power.h"
+#include "tmu.h"
+
+#define TRIMINFO_RELOAD 1
+#define CORE_EN 1
+#define THERM_TRIP_EN (1 << 12)
+
+#define INTEN_RISE0 1
+#define INTEN_RISE1 (1 << 4)
+#define INTEN_RISE2 (1 << 8)
+#define INTEN_FALL0 (1 << 16)
+#define INTEN_FALL1 (1 << 20)
+#define INTEN_FALL2 (1 << 24)
+
+#define TRIM_INFO_MASK 0xff
+
+#define INTCLEAR_RISE0 1
+#define INTCLEAR_RISE1 (1 << 4)
+#define INTCLEAR_RISE2 (1 << 8)
+#define INTCLEAR_FALL0 (1 << 16)
+#define INTCLEAR_FALL1 (1 << 20)
+#define INTCLEAR_FALL2 (1 << 24)
+#define INTCLEARALL (INTCLEAR_RISE0 | INTCLEAR_RISE1 | \
+ INTCLEAR_RISE2 | INTCLEAR_FALL0 | \
+ INTCLEAR_FALL1 | INTCLEAR_FALL2)
+
+struct tmu_info exynos5250_tmu_info = {
+ .tmu_base = 0x10060000,
+ .tmu_mux = 6,
+ .data = {
+ .ts = {
+ .min_val = 25,
+ .max_val = 125,
+ .start_warning = 95,
+ .start_tripping = 105,
+ .hardware_tripping = 110,
+ },
+ .efuse_min_value = 40,
+ .efuse_value = 55,
+ .efuse_max_value = 100,
+ .slope = 0x10008802,
+ },
+ .dc_value = 25,
+};
+
+/*
+ * After reading temperature code from register, compensating
+ * its value and calculating celsius temperature,
+ * get current temperature.
+ *
+ * @return current temperature of the chip as sensed by TMU
+ */
+static int get_cur_temp(struct tmu_info *info)
+{
+ int cur_temp;
+ struct tmu_reg *reg = (struct tmu_reg *)info->tmu_base;
+
+ /* Temperature code range between min 25 and max 125 */
+ cur_temp = readl(®->current_temp) & 0xff;
+
+ /* Calibrate current temperature */
+ if (cur_temp)
+ cur_temp = cur_temp - info->te1 + info->dc_value;
+
+ return cur_temp;
+}
+
+/*
+ * Monitors status of the TMU device and exynos temperature
+ *
+ * @info TMU info
+ * @temp pointer to the current temperature value
+ * @return enum tmu_status_t value, code indicating event to execute
+ */
+enum tmu_status_t tmu_monitor(struct tmu_info *info, int *temp)
+{
+ if (info->tmu_state == TMU_STATUS_INIT)
+ return -1;
+
+ int cur_temp;
+ struct tmu_data *data = &info->data;
+
+ /* Read current temperature of the SOC */
+ cur_temp = get_cur_temp(info);
+ *temp = cur_temp;
+
+ /* Temperature code lies between min 25 and max 125 */
+ if (cur_temp >= data->ts.start_tripping &&
+ cur_temp <= data->ts.max_val)
+ return TMU_STATUS_TRIPPED;
+ else if (cur_temp >= data->ts.start_warning)
+ return TMU_STATUS_WARNING;
+ else if (cur_temp < data->ts.start_warning &&
+ cur_temp >= data->ts.min_val)
+ return TMU_STATUS_NORMAL;
+ /* Temperature code does not lie between min 25 and max 125 */
+ else {
+ info->tmu_state = TMU_STATUS_INIT;
+ printk(BIOS_DEBUG, "EXYNOS_TMU: Thermal reading failed\n");
+ return -1;
+ }
+ return 0;
+}
+
+/*
+ * Calibrate and calculate threshold values and
+ * enable interrupt levels
+ *
+ * @param info pointer to the tmu_info struct
+ */
+static void tmu_setup_parameters(struct tmu_info *info)
+{
+ unsigned int te_temp, con;
+ unsigned int warning_code, trip_code, hwtrip_code;
+ unsigned int cooling_temp;
+ unsigned int rising_value;
+ struct tmu_data *data = &info->data;
+ struct tmu_reg *reg = (struct tmu_reg *)info->tmu_base;
+
+ /* Must reload for using efuse value at EXYNOS */
+ writel(TRIMINFO_RELOAD, ®->triminfo_control);
+
+ /* Get the compensation parameter */
+ te_temp = readl(®->triminfo);
+ info->te1 = te_temp & TRIM_INFO_MASK;
+ info->te2 = ((te_temp >> 8) & TRIM_INFO_MASK);
+
+ if ((data->efuse_min_value > info->te1) ||
+ (info->te1 > data->efuse_max_value)
+ || (info->te2 != 0))
+ info->te1 = data->efuse_value;
+
+ /* Get RISING & FALLING Threshold value */
+ warning_code = data->ts.start_warning
+ + info->te1 - info->dc_value;
+ trip_code = data->ts.start_tripping
+ + info->te1 - info->dc_value;
+ hwtrip_code = data->ts.hardware_tripping
+ + info->te1 - info->dc_value;
+
+ cooling_temp = 0;
+
+ rising_value = ((warning_code << 8) |
+ (trip_code << 16) |
+ (hwtrip_code << 24));
+
+ /* Set interrupt level */
+ writel(rising_value, ®->threshold_temp_rise);
+ writel(cooling_temp, ®->threshold_temp_fall);
+
+ /*
+ * Need to init all register settings after getting parameter info
+ * [28:23] vref [11:8] slope - Tuning parameter
+ *
+ * WARNING: this slope value writes into many bits in the tmu_control
+ * register, with the default FDT value of 268470274 (0x10008802)
+ * we are using this essentially sets the default register setting
+ * from the TRM for tmu_control.
+ * TODO(bhthompson): rewrite this code such that we are not performing
+ * a hard wipe of tmu_control and re verify functionality.
+ */
+ writel(data->slope, ®->tmu_control);
+
+ writel(INTCLEARALL, ®->intclear);
+ /* TMU core enable */
+ con = readl(®->tmu_control);
+ con |= (info->tmu_mux << 20) | THERM_TRIP_EN | CORE_EN;
+
+ writel(con, ®->tmu_control);
+
+ /* Enable HW thermal trip */
+ power_enable_hw_thermal_trip();
+
+ /* LEV1 LEV2 interrupt enable */
+ writel(INTEN_RISE1 | INTEN_RISE2, ®->inten);
+}
+
+/*
+ * Initialize TMU device
+ *
+ * @return int value, 0 for success
+ */
+int tmu_init(struct tmu_info *info)
+{
+ info->tmu_state = TMU_STATUS_INIT;
+
+ tmu_setup_parameters(info);
+ info->tmu_state = TMU_STATUS_NORMAL;
+
+ return 0;
+}
diff --git a/src/soc/samsung/exynos5250/tmu.h b/src/soc/samsung/exynos5250/tmu.h
new file mode 100644
index 0000000..bda4bd7
--- /dev/null
+++ b/src/soc/samsung/exynos5250/tmu.h
@@ -0,0 +1,134 @@
+/*
+ * This file is part of the coreboot project.
+ *
+ * Copyright (c) 2012 Samsung Electronics Co., Ltd.
+ *
+ * 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
+ */
+
+/* EXYNOS - Thermal Management Unit */
+
+#ifndef CPU_SAMSUNG_EXYNOS5250_TMU_H
+#define CPU_SAMSUNG_EXYNOS5250_TMU_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,
+};
+
+/* Temperature threshold values for various thermal events */
+struct temperature_params {
+ /* minimum value in temperature code range */
+ unsigned int min_val;
+ /* maximum value in temperature code range */
+ unsigned int max_val;
+ /* temperature threshold to start warning */
+ unsigned int start_warning;
+ /* temperature threshold CPU tripping */
+ unsigned int start_tripping;
+ /* temperature threshold for HW tripping */
+ unsigned int hardware_tripping;
+};
+
+/* Pre-defined values and thresholds for calibration of current temperature */
+struct tmu_data {
+ /* pre-defined temperature thresholds */
+ struct temperature_params ts;
+ /* pre-defined efuse range minimum value */
+ unsigned int efuse_min_value;
+ /* pre-defined efuse value for temperature calibration */
+ unsigned int efuse_value;
+ /* pre-defined efuse range maximum value */
+ unsigned int efuse_max_value;
+ /* current temperature sensing slope */
+ unsigned int slope;
+};
+
+/* TMU device specific details and status */
+struct tmu_info {
+ /* base Address for the TMU */
+ unsigned tmu_base;
+ /* mux Address for the TMU */
+ int tmu_mux;
+ /* pre-defined values for calibration and thresholds */
+ struct tmu_data data;
+ /* value required for triminfo_25 calibration */
+ unsigned int te1;
+ /* value required for triminfo_85 calibration */
+ unsigned int te2;
+ /* TMU DC value for threshold calculation */
+ int dc_value;
+ /* enum value indicating status of the TMU */
+ int tmu_state;
+};
+
+extern struct tmu_info *tmu_info;
+
+/*
+ * Monitors status of the TMU device and exynos temperature
+ *
+ * @info pointer to TMU info struct
+ * @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(struct tmu_info *info, int *temp);
+
+/*
+ * Initialize TMU device
+ *
+ * @info pointer to TMU info struct
+ * @return int value, 0 for success
+ */
+int tmu_init(struct tmu_info *info);
+
+#endif /* CPU_SAMSUNG_EXYNOS5250_TMU_H */
diff --git a/src/soc/samsung/exynos5250/trustzone.c b/src/soc/samsung/exynos5250/trustzone.c
new file mode 100644
index 0000000..d67eb33
--- /dev/null
+++ b/src/soc/samsung/exynos5250/trustzone.c
@@ -0,0 +1,44 @@
+/*
+ * This file is part of the coreboot project.
+ *
+ * Copyright 2013 Google Inc.
+ * 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; 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 <arch/io.h>
+#include "trustzone.h"
+
+/* Setting TZPC[TrustZone Protection Controller] */
+void trustzone_init(void)
+{
+ struct exynos_tzpc *tzpc;
+ unsigned int addr;
+
+ for (addr = TZPC0_BASE; addr <= TZPC9_BASE; addr += TZPC_BASE_OFFSET) {
+ tzpc = (struct exynos_tzpc *)addr;
+
+ if (addr == TZPC0_BASE)
+ writel(R0SIZE, &tzpc->r0size);
+
+ writel(DECPROTXSET, &tzpc->decprot0set);
+ writel(DECPROTXSET, &tzpc->decprot1set);
+
+ if (addr != TZPC9_BASE) {
+ writel(DECPROTXSET, &tzpc->decprot2set);
+ writel(DECPROTXSET, &tzpc->decprot3set);
+ }
+ }
+}
diff --git a/src/soc/samsung/exynos5250/trustzone.h b/src/soc/samsung/exynos5250/trustzone.h
new file mode 100644
index 0000000..7b4af9b
--- /dev/null
+++ b/src/soc/samsung/exynos5250/trustzone.h
@@ -0,0 +1,81 @@
+/*
+ * This file is part of the coreboot project.
+ *
+ * Copyright 2013 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
+ */
+
+#ifndef CPU_SAMSUNG_EXYNOS5250_TRUSTZONE_H
+#define CPU_SAMSUNG_EXYNOS5250_TRUSTZONE_H
+
+#include <stdint.h>
+
+/* Distance between each Trust Zone PC register set */
+#define TZPC_BASE_OFFSET 0x10000
+/* TZPC : Register Offsets */
+#define TZPC0_BASE 0x10100000
+#define TZPC1_BASE 0x10110000
+#define TZPC2_BASE 0x10120000
+#define TZPC3_BASE 0x10130000
+#define TZPC4_BASE 0x10140000
+#define TZPC5_BASE 0x10150000
+#define TZPC6_BASE 0x10160000
+#define TZPC7_BASE 0x10170000
+#define TZPC8_BASE 0x10180000
+#define TZPC9_BASE 0x10190000
+#define TZPC10_BASE 0x100E0000
+#define TZPC11_BASE 0x100F0000
+
+/*
+ * TZPC Register Value :
+ * R0SIZE: 0x0 : Size of secured ram
+ */
+#define R0SIZE 0x0
+
+/*
+ * TZPC Decode Protection Register Value :
+ * DECPROTXSET: 0xFF : Set Decode region to non-secure
+ */
+#define DECPROTXSET 0xFF
+
+struct exynos_tzpc {
+ u32 r0size;
+ u8 res1[0x7FC];
+ u32 decprot0stat;
+ u32 decprot0set;
+ u32 decprot0clr;
+ u32 decprot1stat;
+ u32 decprot1set;
+ u32 decprot1clr;
+ u32 decprot2stat;
+ u32 decprot2set;
+ u32 decprot2clr;
+ u32 decprot3stat;
+ u32 decprot3set;
+ u32 decprot3clr;
+ u8 res2[0x7B0];
+ u32 periphid0;
+ u32 periphid1;
+ u32 periphid2;
+ u32 periphid3;
+ u32 pcellid0;
+ u32 pcellid1;
+ u32 pcellid2;
+ u32 pcellid3;
+};
+
+void trustzone_init(void);
+
+#endif /* CPU_SAMSUNG_EXYNOS5250_TRUSTZONE_H */
diff --git a/src/soc/samsung/exynos5250/uart.c b/src/soc/samsung/exynos5250/uart.c
new file mode 100644
index 0000000..cc97291
--- /dev/null
+++ b/src/soc/samsung/exynos5250/uart.c
@@ -0,0 +1,203 @@
+/*
+ * This file is part of the coreboot project.
+ *
+ * Copyright (C) 2009 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; 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 <types.h>
+#include <console/uart.h>
+#include <arch/io.h>
+#include <boot/coreboot_tables.h>
+#include "uart.h"
+#include "clk.h"
+#include "cpu.h"
+#include "periph.h"
+#include "uart.h"
+
+#define RX_FIFO_COUNT_MASK 0xff
+#define RX_FIFO_FULL_MASK (1 << 8)
+#define TX_FIFO_FULL_MASK (1 << 24)
+
+
+/*
+ * 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 recommend 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(struct s5p_uart *uart)
+{
+ u32 uclk;
+ u32 val;
+
+ // All UARTs share the same clock.
+ uclk = clock_get_periph_rate(PERIPH_ID_UART3);
+ val = uclk / default_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())
+ writel(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(struct s5p_uart *uart)
+{
+ // TODO initialize with correct peripheral id by base_port.
+ exynos_pinmux_uart3();
+
+ /* 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(uart);
+}
+
+static int exynos5_uart_err_check(struct s5p_uart *uart, int op)
+{
+ 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 successful, the character read is
+ * written into its argument c.
+ */
+static unsigned char exynos5_uart_rx_byte(struct s5p_uart *uart)
+{
+ /* wait for character to arrive */
+ while (!(readl(&uart->ufstat) & (RX_FIFO_COUNT_MASK |
+ RX_FIFO_FULL_MASK))) {
+ if (exynos5_uart_err_check(uart, 0))
+ return 0;
+ }
+
+ return readb(&uart->urxh) & 0xff;
+}
+
+/*
+ * Output a single byte to the serial port.
+ */
+static void exynos5_uart_tx_byte(struct s5p_uart *uart, unsigned char data)
+{
+ /* wait for room in the tx FIFO */
+ while ((readl(&uart->ufstat) & TX_FIFO_FULL_MASK)) {
+ if (exynos5_uart_err_check(uart, 1))
+ return;
+ }
+
+ writeb(data, &uart->utxh);
+}
+
+static void exynos5_uart_tx_flush(struct s5p_uart *uart)
+{
+ while (readl(&uart->ufstat) & 0x1ff0000);
+}
+
+unsigned int uart_platform_base(int idx)
+{
+ if (idx < 4)
+ return 0x12c00000 + idx * 0x10000;
+ else
+ return 0;
+}
+
+void uart_init(int idx)
+{
+ struct s5p_uart *uart = uart_platform_baseptr(idx);
+ exynos5_init_dev(uart);
+}
+
+unsigned char uart_rx_byte(int idx)
+{
+ struct s5p_uart *uart = uart_platform_baseptr(idx);
+ return exynos5_uart_rx_byte(uart);
+}
+
+void uart_tx_byte(int idx, unsigned char data)
+{
+ struct s5p_uart *uart = uart_platform_baseptr(idx);
+ exynos5_uart_tx_byte(uart, data);
+}
+
+void uart_tx_flush(int idx)
+{
+ struct s5p_uart *uart = uart_platform_baseptr(idx);
+ exynos5_uart_tx_flush(uart);
+}
+
+#ifndef __PRE_RAM__
+void uart_fill_lb(void *data)
+{
+ struct lb_serial serial;
+ serial.type = LB_SERIAL_TYPE_MEMORY_MAPPED;
+ serial.baseaddr = uart_platform_base(CONFIG_UART_FOR_CONSOLE);
+ serial.baud = default_baudrate();
+ lb_add_serial(&serial, data);
+
+ lb_add_console(LB_TAG_CONSOLE_SERIAL8250MEM, data);
+}
+#endif
diff --git a/src/soc/samsung/exynos5250/uart.h b/src/soc/samsung/exynos5250/uart.h
new file mode 100644
index 0000000..d324a2f
--- /dev/null
+++ b/src/soc/samsung/exynos5250/uart.h
@@ -0,0 +1,48 @@
+/*
+ * This file is part of the coreboot project.
+ *
+ * Copyright 2012 Google Inc.
+ * Copyright (C) 2009 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; 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
+ */
+
+#ifndef CPU_SAMSUNG_EXYNOS5250_UART_H
+#define CPU_SAMSUNG_EXYNOS5250_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];
+};
+
+#endif
diff --git a/src/soc/samsung/exynos5250/usb.c b/src/soc/samsung/exynos5250/usb.c
new file mode 100644
index 0000000..76da1dd
--- /dev/null
+++ b/src/soc/samsung/exynos5250/usb.c
@@ -0,0 +1,198 @@
+/*
+ * This file is part of the coreboot project.
+ *
+ * Copyright (C) 2012 Samsung Electronics
+ * Copyright 2013 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 <delay.h>
+#include <arch/io.h>
+#include <console/console.h>
+#include <device/device.h>
+#include "gpio.h"
+#include "power.h"
+#include "sysreg.h"
+#include "usb.h"
+
+static void reset_dwc3(struct exynos5_usb_drd_dwc3 *dwc3)
+{
+ setbits_le32(&dwc3->ctl, 0x1 << 11); /* core soft reset */
+ setbits_le32(&dwc3->usb3pipectl, 0x1 << 31); /* PHY soft reset */
+ setbits_le32(&dwc3->usb2phycfg, 0x1 << 31); /* PHY soft reset */
+}
+
+void reset_usb_drd_dwc3()
+{
+ printk(BIOS_DEBUG, "Starting DWC3 reset for USB DRD\n");
+ reset_dwc3(exynos_usb_drd_dwc3);
+}
+
+static void setup_dwc3(struct exynos5_usb_drd_dwc3 *dwc3)
+{
+ if (!(dwc3->ctl & 0x1 << 11) ||
+ !(dwc3->usb3pipectl & 0x1 << 31) ||
+ !(dwc3->usb2phycfg & 0x1 << 31)) {
+ printk(BIOS_ERR, "DWC3 at %p not in reset (you need to call "
+ "reset_usb_drd_dwc3() first)!\n", dwc3);
+ }
+
+ /* Set relevant registers to default values (clearing all reset bits) */
+
+ writel(0x1 << 24 | /* activate PHY low power states */
+ 0x4 << 19 | /* low power delay value */
+ 0x1 << 18 | /* activate PHY low power delay */
+ 0x1 << 17 | /* enable SuperSpeed PHY suspend */
+ 0x1 << 1 | /* default Tx deemphasis value */
+ 0, &dwc3->usb3pipectl);
+
+ /* Configure PHY clock turnaround for 8-bit UTMI+, disable suspend */
+ writel(0x9 << 10 | /* PHY clock turnaround for 8-bit UTMI+ */
+ 0x1 << 8 | /* enable PHY sleep in L1 */
+ 0x1 << 6 | /* enable PHY suspend */
+ 0, &dwc3->usb2phycfg);
+
+ writel(0x5dc << 19 | /* suspend clock scale for 24MHz */
+ 0x1 << 16 | /* retry SS three times (bugfix from U-Boot) */
+ 0x1 << 12 | /* port capability HOST */
+ 0, &dwc3->ctl);
+}
+
+void setup_usb_drd_dwc3()
+{
+ setup_dwc3(exynos_usb_drd_dwc3);
+ printk(BIOS_DEBUG, "DWC3 setup for USB DRD finished\n");
+}
+
+static void setup_drd_phy(struct exynos5_usb_drd_phy *phy)
+{
+ /* Set all PHY registers to default values */
+
+ /* XHCI Version 1.0, Frame Length adjustment 30 MHz */
+ setbits_le32(&phy->linksystem, 0x1 << 27 | 0x20 << 1);
+
+ /* Disable OTG, ID0 and DRVVBUS, do not force sleep/suspend */
+ writel(1 << 6, &phy->utmi);
+
+ writel(0x88 << 23 | /* spread spectrum refclk selector */
+ 0x1 << 20 | /* enable spread spectrum */
+ 0x1 << 19 | /* enable prescaler refclk */
+ 0x68 << 11 | /* multiplier for 24MHz refclk */
+ 0x5 << 5 | /* select 24MHz refclk (weird, from U-Boot) */
+ 0x1 << 4 | /* power supply in normal operating mode */
+ 0x3 << 2 | /* use external refclk (undocumented on 5420?)*/
+ 0x1 << 1 | /* force port reset */
+ 0x1 << 0 | /* normal operating mode */
+ 0, &phy->clkrst);
+
+ writel(0x9 << 26 | /* LOS level */
+ 0x3 << 22 | /* TX VREF tune */
+ 0x1 << 20 | /* TX rise tune */
+ 0x1 << 18 | /* TX res tune */
+ 0x3 << 13 | /* TX HS X Vtune */
+ 0x3 << 9 | /* TX FS/LS tune */
+ 0x3 << 6 | /* SQRX tune */
+ 0x4 << 3 | /* OTG tune */
+ 0x4 << 0 | /* comp disc tune */
+ 0, &phy->param0);
+
+ writel(0x7f << 19 | /* reserved */
+ 0x7f << 12 | /* Tx launch amplitude */
+ 0x20 << 6 | /* Tx deemphasis 6dB */
+ 0x1c << 0 | /* Tx deemphasis 3.5dB (value from U-Boot) */
+ 0, &phy->param1);
+
+ /* disable all test features */
+ writel(0, &phy->test);
+
+ /* UTMI clock select? ("must be 0x1") */
+ writel(0x1 << 2, &phy->utmiclksel);
+
+ /* Samsung magic, undocumented (from U-Boot) */
+ writel(0x0, &phy->resume);
+
+ udelay(10);
+ clrbits_le32(&phy->clkrst, 0x1 << 1); /* deassert port reset */
+}
+
+void setup_usb_drd_phy()
+{
+ printk(BIOS_DEBUG, "Powering up USB DRD PHY\n");
+ setbits_le32(&exynos_power->usb_drd_phy_ctrl, POWER_USB_PHY_CTRL_EN);
+ setup_drd_phy(exynos_usb_drd_phy);
+}
+
+void setup_usb_host_phy(int hsic_gpio)
+{
+ unsigned int hostphy_ctrl0;
+
+ setbits_le32(&exynos_sysreg->usb20_phy_cfg, USB20_PHY_CFG_EN);
+ setbits_le32(&exynos_power->usb_host_phy_ctrl, POWER_USB_PHY_CTRL_EN);
+
+ printk(BIOS_DEBUG, "Powering up USB HOST PHY (%s HSIC)\n",
+ hsic_gpio ? "with" : "without");
+
+ hostphy_ctrl0 = readl(&exynos_usb_host_phy->usbphyctrl0);
+ hostphy_ctrl0 &= ~(HOST_CTRL0_FSEL_MASK |
+ HOST_CTRL0_COMMONON_N |
+ /* HOST Phy setting */
+ HOST_CTRL0_PHYSWRST |
+ HOST_CTRL0_PHYSWRSTALL |
+ HOST_CTRL0_SIDDQ |
+ HOST_CTRL0_FORCESUSPEND |
+ HOST_CTRL0_FORCESLEEP);
+ hostphy_ctrl0 |= (/* Setting up the ref freq */
+ CLK_24MHZ << 16 |
+ /* HOST Phy setting */
+ HOST_CTRL0_LINKSWRST |
+ HOST_CTRL0_UTMISWRST);
+ writel(hostphy_ctrl0, &exynos_usb_host_phy->usbphyctrl0);
+ udelay(10);
+ clrbits_le32(&exynos_usb_host_phy->usbphyctrl0,
+ HOST_CTRL0_LINKSWRST |
+ HOST_CTRL0_UTMISWRST);
+ udelay(20);
+
+ /* EHCI Ctrl setting */
+ setbits_le32(&exynos_usb_host_phy->ehcictrl,
+ EHCICTRL_ENAINCRXALIGN |
+ EHCICTRL_ENAINCR4 |
+ EHCICTRL_ENAINCR8 |
+ EHCICTRL_ENAINCR16);
+
+ /* HSIC USB Hub initialization. */
+ if (hsic_gpio) {
+ gpio_direction_output(hsic_gpio, 0);
+ udelay(100);
+ gpio_direction_output(hsic_gpio, 1);
+ udelay(5000);
+
+ clrbits_le32(&exynos_usb_host_phy->hsicphyctrl1,
+ HOST_CTRL0_SIDDQ |
+ HOST_CTRL0_FORCESLEEP |
+ HOST_CTRL0_FORCESUSPEND);
+ setbits_le32(&exynos_usb_host_phy->hsicphyctrl1,
+ HOST_CTRL0_PHYSWRST);
+ udelay(10);
+ clrbits_le32(&exynos_usb_host_phy->hsicphyctrl1,
+ HOST_CTRL0_PHYSWRST);
+ }
+
+ /* At this point we need to wait for 50ms before talking to
+ * the USB controller (PHY clock and power setup time)
+ * By the time we are actually in the payload, these 50ms
+ * will have passed.
+ */
+}
diff --git a/src/soc/samsung/exynos5250/usb.h b/src/soc/samsung/exynos5250/usb.h
new file mode 100644
index 0000000..ad617da
--- /dev/null
+++ b/src/soc/samsung/exynos5250/usb.h
@@ -0,0 +1,137 @@
+/*
+ * This file is part of the coreboot project.
+ *
+ * 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; 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
+ */
+
+#ifndef CPU_SAMSUNG_EXYNOS5250_USB_H
+#define CPU_SAMSUNG_EXYNOS5250_USB_H
+
+#include "cpu.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 exynos5_usb_host_phy {
+ uint32_t usbphyctrl0;
+ uint32_t usbphytune0;
+ uint8_t reserved1[8];
+ uint32_t hsicphyctrl1;
+ uint32_t hsicphytune1;
+ uint8_t reserved2[8];
+ uint32_t hsicphyctrl2;
+ uint32_t hsicphytune2;
+ uint8_t reserved3[8];
+ uint32_t ehcictrl;
+ uint32_t ohcictrl;
+ uint32_t usbotgsys;
+ uint8_t reserved4[4];
+ uint32_t usbotgtune;
+};
+
+static struct exynos5_usb_host_phy * const exynos_usb_host_phy =
+ (void *)EXYNOS5_USB_HOST_PHY_BASE;
+
+struct exynos5_usb_drd_phy {
+ uint8_t reserved1[4];
+ uint32_t linksystem;
+ uint32_t utmi;
+ uint32_t pipe;
+ uint32_t clkrst;
+ uint32_t reg0;
+ uint32_t reg1;
+ uint32_t param0;
+ uint32_t param1;
+ uint32_t term;
+ uint32_t test;
+ uint32_t adp;
+ uint32_t utmiclksel;
+ uint32_t resume;
+ uint8_t reserved2[8];
+ uint32_t linkhcbelt;
+ uint32_t linkport;
+};
+
+static struct exynos5_usb_drd_phy * const exynos_usb_drd_phy =
+ (void *)EXYNOS5_USB_DRD_PHY_BASE;
+
+struct exynos5_usb_drd_dwc3 {
+ uint32_t sbuscfg0;
+ uint32_t sbuscfg1;
+ uint32_t txthrcfg;
+ uint32_t rxthrcfg;
+ uint32_t ctl;
+ uint32_t evten;
+ uint32_t sts;
+ uint8_t reserved0[4];
+ uint32_t snpsid;
+ uint32_t gpio;
+ uint32_t uid;
+ uint32_t uctl;
+ uint64_t buserraddr;
+ uint64_t prtbimap;
+ uint8_t reserved1[32];
+ uint32_t dbgfifospace;
+ uint32_t dbgltssm;
+ uint32_t dbglnmcc;
+ uint32_t dbgbmu;
+ uint32_t dbglspmux;
+ uint32_t dbglsp;
+ uint32_t dbgepinfo0;
+ uint32_t dbgepinfo1;
+ uint64_t prtbimap_hs;
+ uint64_t prtbimap_fs;
+ uint8_t reserved2[112];
+ uint32_t usb2phycfg;
+ uint8_t reserved3[60];
+ uint32_t usb2i2cctl;
+ uint8_t reserved4[60];
+ uint32_t usb2phyacc;
+ uint8_t reserved5[60];
+ uint32_t usb3pipectl;
+ uint8_t reserved6[60];
+};
+
+static struct exynos5_usb_drd_dwc3 * const exynos_usb_drd_dwc3 =
+ (void *)EXYNOS5_USB_DRD_DWC3_BASE;
+
+/* Leave hsic_gpio at 0 to not enable HSIC. */
+void setup_usb_host_phy(int hsic_gpio);
+
+void setup_usb_drd_phy(void);
+
+/* Call reset_ before setup_, ensure at least 100ms pass in between. */
+void reset_usb_drd_dwc3(void);
+void setup_usb_drd_dwc3(void);
+
+#endif
diff --git a/src/soc/samsung/exynos5250/wakeup.c b/src/soc/samsung/exynos5250/wakeup.c
new file mode 100644
index 0000000..b7161cf
--- /dev/null
+++ b/src/soc/samsung/exynos5250/wakeup.c
@@ -0,0 +1,55 @@
+/*
+ * This file is part of the coreboot project.
+ *
+ * Copyright 2013 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 <console/console.h>
+#include "power.h"
+#include "wakeup.h"
+
+void wakeup(void)
+{
+ if (wakeup_need_reset())
+ power_reset();
+
+ power_init(); /* Ensure ps_hold_setup() for early wakeup. */
+ power_exit_wakeup();
+ /* Should never return. If we do, reset. */
+ power_reset();
+}
+
+int get_wakeup_state(void)
+{
+ uint32_t status = power_read_reset_status();
+
+ /* DIDLE/LPA can be resumed without clock reset (ex, bootblock),
+ * and SLEEP requires resetting clock (should be done in ROM stage).
+ */
+
+ if (status == S5P_CHECK_DIDLE || status == S5P_CHECK_LPA)
+ return WAKEUP_DIRECT;
+
+ if (status == S5P_CHECK_SLEEP)
+ return WAKEUP_NEED_CLOCK_RESET;
+
+ return IS_NOT_WAKEUP;
+}
+
+void wakeup_enable_uart(void)
+{
+ power_release_uart_retention();
+}
diff --git a/src/soc/samsung/exynos5250/wakeup.h b/src/soc/samsung/exynos5250/wakeup.h
new file mode 100644
index 0000000..690c6a3
--- /dev/null
+++ b/src/soc/samsung/exynos5250/wakeup.h
@@ -0,0 +1,43 @@
+/*
+ * This file is part of the coreboot project.
+ *
+ * Copyright 2013 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
+ */
+
+#ifndef CPU_SAMSUNG_EXYNOS5250_WAKEUP_H
+#define CPU_SAMSUNG_EXYNOS5250_WAKEUP_H
+
+/* Power Down Modes */
+#define S5P_CHECK_SLEEP 0x00000BAD
+#define S5P_CHECK_DIDLE 0xBAD00000
+#define S5P_CHECK_LPA 0xABAD0000
+
+enum {
+ // A normal boot (not suspend/resume)
+ IS_NOT_WAKEUP,
+ // A wake up event that can be resumed any time
+ WAKEUP_DIRECT,
+ // A wake up event that must be resumed only after
+ // clock and memory controllers are re-initialized
+ WAKEUP_NEED_CLOCK_RESET,
+};
+
+int wakeup_need_reset(void);
+int get_wakeup_state(void);
+void wakeup(void);
+void wakeup_enable_uart(void);
+
+#endif /* CPU_SAMSUNG_EXYNOS5250_WAKEUP_H */