[coreboot-gerrit] New patch to review for coreboot: 8b528f7 pit: Create an exynos5420 directory which is nearly a copy of exynos5250.

Gabe Black (gabeblack@chromium.org) gerrit at coreboot.org
Tue Jul 9 05:28:58 CEST 2013


Gabe Black (gabeblack at chromium.org) just uploaded a new patch set to gerrit, which you can find at http://review.coreboot.org/3644

-gerrit

commit 8b528f795f65dd097cfe642c48ae1df516722890
Author: Gabe Black <gabeblack at google.com>
Date:   Thu May 16 05:45:57 2013 -0700

    pit: Create an exynos5420 directory which is nearly a copy of exynos5250.
    
    This change creates an exynos5420 directory with code that will eventually
    implement support for the exynos5420 cpu from Samsung. Currently it's a copy
    of the exynos5250 directory with the name changed. There are going to be some
    problems where headers in src/cpu/samsung/exynos-common include headers in the
    exynos5250 directory directly.
    
    Change-Id: Ia8d7244310d32499238bbc171c0c668ec48178e1
    Signed-off-by: Gabe Black <gabeblack at chromium.org>
---
 src/cpu/samsung/Kconfig                      |  16 +-
 src/cpu/samsung/Makefile.inc                 |   3 +-
 src/cpu/samsung/exynos5420/Kconfig           | 133 +++++
 src/cpu/samsung/exynos5420/Makefile.inc      |  55 ++
 src/cpu/samsung/exynos5420/bootblock.c       |  43 ++
 src/cpu/samsung/exynos5420/chip.h            |  40 ++
 src/cpu/samsung/exynos5420/clk.h             | 624 ++++++++++++++++++++++
 src/cpu/samsung/exynos5420/clock.c           | 691 ++++++++++++++++++++++++
 src/cpu/samsung/exynos5420/clock_init.c      | 445 ++++++++++++++++
 src/cpu/samsung/exynos5420/cpu.c             | 181 +++++++
 src/cpu/samsung/exynos5420/cpu.h             | 130 +++++
 src/cpu/samsung/exynos5420/dmc.h             | 343 ++++++++++++
 src/cpu/samsung/exynos5420/dmc_common.c      | 183 +++++++
 src/cpu/samsung/exynos5420/dmc_init_ddr3.c   | 277 ++++++++++
 src/cpu/samsung/exynos5420/dp-core.h         | 268 ++++++++++
 src/cpu/samsung/exynos5420/dp-reg.c          | 495 ++++++++++++++++++
 src/cpu/samsung/exynos5420/dp.h              | 497 ++++++++++++++++++
 src/cpu/samsung/exynos5420/dsim.h            | 109 ++++
 src/cpu/samsung/exynos5420/fb.c              | 597 +++++++++++++++++++++
 src/cpu/samsung/exynos5420/fimd.h            | 138 +++++
 src/cpu/samsung/exynos5420/gpio.c            | 279 ++++++++++
 src/cpu/samsung/exynos5420/gpio.h            | 578 ++++++++++++++++++++
 src/cpu/samsung/exynos5420/i2c.c             | 405 ++++++++++++++
 src/cpu/samsung/exynos5420/i2c.h             |  41 ++
 src/cpu/samsung/exynos5420/i2s-regs.h        | 142 +++++
 src/cpu/samsung/exynos5420/mct.c             | 104 ++++
 src/cpu/samsung/exynos5420/monotonic_timer.c |  57 ++
 src/cpu/samsung/exynos5420/periph.h          |  69 +++
 src/cpu/samsung/exynos5420/pinmux.c          | 298 +++++++++++
 src/cpu/samsung/exynos5420/pinmux.h          |  55 ++
 src/cpu/samsung/exynos5420/power.c           | 138 +++++
 src/cpu/samsung/exynos5420/power.h           |  90 ++++
 src/cpu/samsung/exynos5420/pwm.c             | 191 +++++++
 src/cpu/samsung/exynos5420/pwm.h             |  70 +++
 src/cpu/samsung/exynos5420/reset.c           |  26 +
 src/cpu/samsung/exynos5420/setup.h           | 753 +++++++++++++++++++++++++++
 src/cpu/samsung/exynos5420/spi.c             | 222 ++++++++
 src/cpu/samsung/exynos5420/spi.h             |  98 ++++
 src/cpu/samsung/exynos5420/sysreg.h          |  37 ++
 src/cpu/samsung/exynos5420/timer.c           | 110 ++++
 src/cpu/samsung/exynos5420/timer.h           |  25 +
 src/cpu/samsung/exynos5420/tmu.c             | 215 ++++++++
 src/cpu/samsung/exynos5420/tmu.h             | 134 +++++
 src/cpu/samsung/exynos5420/uart.c            | 200 +++++++
 src/cpu/samsung/exynos5420/uart.h            |  54 ++
 src/cpu/samsung/exynos5420/wakeup.c          |  50 ++
 src/cpu/samsung/exynos5420/wakeup.h          |  42 ++
 src/mainboard/google/snow/Kconfig            |   2 +-
 48 files changed, 9749 insertions(+), 4 deletions(-)

diff --git a/src/cpu/samsung/Kconfig b/src/cpu/samsung/Kconfig
index 9e2ec4c..3b6df9e 100644
--- a/src/cpu/samsung/Kconfig
+++ b/src/cpu/samsung/Kconfig
@@ -1,4 +1,4 @@
-config CPU_SAMSUNG_EXYNOS5
+config CPU_SAMSUNG_EXYNOS5250
 	depends on ARCH_ARMV7
 	select HAVE_MONOTONIC_TIMER
 	select HAVE_UART_SPECIAL
@@ -6,6 +6,18 @@ config CPU_SAMSUNG_EXYNOS5
 	bool
 	default n
 
-if CPU_SAMSUNG_EXYNOS5
+config CPU_SAMSUNG_EXYNOS5420
+	depends on ARCH_ARMV7
+	select HAVE_MONOTONIC_TIMER
+	select HAVE_UART_SPECIAL
+	select DEFAULT_EARLY_CONSOLE
+	bool
+	default n
+
+if CPU_SAMSUNG_EXYNOS5250
 source src/cpu/samsung/exynos5250/Kconfig
 endif
+
+if CPU_SAMSUNG_EXYNOS5420
+source src/cpu/samsung/exynos5420/Kconfig
+endif
diff --git a/src/cpu/samsung/Makefile.inc b/src/cpu/samsung/Makefile.inc
index 9110983..496b5f7 100644
--- a/src/cpu/samsung/Makefile.inc
+++ b/src/cpu/samsung/Makefile.inc
@@ -1 +1,2 @@
-subdirs-$(CONFIG_CPU_SAMSUNG_EXYNOS5) += exynos5250
+subdirs-$(CONFIG_CPU_SAMSUNG_EXYNOS5250) += exynos5250
+subdirs-$(CONFIG_CPU_SAMSUNG_EXYNOS5420) += exynos5420
diff --git a/src/cpu/samsung/exynos5420/Kconfig b/src/cpu/samsung/exynos5420/Kconfig
new file mode 100644
index 0000000..2f7ea94
--- /dev/null
+++ b/src/cpu/samsung/exynos5420/Kconfig
@@ -0,0 +1,133 @@
+config BOOTBLOCK_CPU_INIT
+	string
+	default "cpu/samsung/exynos5420/bootblock.c"
+	help
+	  CPU/SoC-specific bootblock code. This is useful if the
+	  bootblock must load microcode or copy data from ROM before
+	  searching for the bootblock.
+
+config EXYNOS_ACE_SHA
+	bool
+	default n
+
+config BL1_SIZE_KB
+	int
+	default 8
+
+# Example SRAM/iRAM map for Exynos5420 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 ROMSTAGE_SIZE
+	hex
+	default 0x10000
+
+# 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 0x02077000
+
+config STACK_SIZE
+	hex
+	default 0x1000
+
+config CBFS_ROM_OFFSET
+	# Calculated by BL1 + max bootblock size.
+	hex "offset of CBFS data in ROM"
+	default 0x0A000
+
+# TODO Change this to some better address not overlapping bootblock when
+# cbfstool supports creating header in arbitrary location.
+config CBFS_HEADER_ROM_OFFSET
+	hex "offset of master CBFS header in ROM"
+	default 0x2040
+
+# 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 0x02060000
+
+config CBFS_CACHE_SIZE
+	hex "size of CBFS cache data"
+	default 0x000017000
+
+# FIXME: This is for copying SPI content into SRAM temporarily and
+# will be removed when we have the SPI streaming driver implemented.
+config SPI_IMAGE_HACK
+	hex
+	default 0x02060000
+
+# FIXME: other magic numbers that should probably go away
+config XIP_ROM_SIZE
+	hex
+	default ROMSTAGE_SIZE
+
+config SYS_SDRAM_BASE
+	hex
+	default 0x40000000
+
+config SYS_TEXT_BASE
+	hex
+	default 0x43e00000
+
+config COREBOOT_TABLES_SIZE
+	hex
+	default 0x4000000
+
+choice CONSOLE_SERIAL_UART_CHOICES
+	prompt "Serial Console UART"
+	default CONSOLE_SERIAL_UART3
+	depends on CONSOLE_SERIAL_UART
+
+config CONSOLE_SERIAL_UART0
+	bool "UART0"
+	help
+	  Serial console on UART0
+
+config CONSOLE_SERIAL_UART1
+	bool "UART1"
+	help
+	  Serial console on UART1
+
+config CONSOLE_SERIAL_UART2
+	bool "UART2"
+	help
+	  Serial console on UART2
+
+config CONSOLE_SERIAL_UART3
+	bool "UART3"
+	help
+	  Serial console on UART3
+
+endchoice
+
+config CONSOLE_SERIAL_UART_ADDRESS
+	hex
+	depends on CONSOLE_SERIAL_UART
+	default 0x12c00000 if CONSOLE_SERIAL_UART0
+	default 0x12c10000 if CONSOLE_SERIAL_UART1
+	default 0x12c20000 if CONSOLE_SERIAL_UART2
+	default 0x12c30000 if CONSOLE_SERIAL_UART3
+	help
+	  Map the UART names to the respective MMIO address.
+
diff --git a/src/cpu/samsung/exynos5420/Makefile.inc b/src/cpu/samsung/exynos5420/Makefile.inc
new file mode 100644
index 0000000..4099b12
--- /dev/null
+++ b/src/cpu/samsung/exynos5420/Makefile.inc
@@ -0,0 +1,55 @@
+# Run an intermediate step when producing coreboot.rom
+# that adds additional components to the final firmware
+# image outside of CBFS
+INTERMEDIATE += exynos5420_add_bl1
+
+bootblock-y += spi.c
+bootblock-y += pinmux.c mct.c power.c
+# Clock is required for UART
+bootblock-$(CONFIG_EARLY_CONSOLE) += clock_init.c
+bootblock-$(CONFIG_EARLY_CONSOLE) += clock.c
+bootblock-$(CONFIG_EARLY_CONSOLE) += monotonic_timer.c
+bootblock-$(CONFIG_EARLY_CONSOLE) += uart.c
+bootblock-y += wakeup.c
+bootblock-y += gpio.c
+bootblock-$(CONFIG_EARLY_CONSOLE) += pwm.c
+bootblock-$(CONFIG_EARLY_CONSOLE) += timer.c
+
+romstage-y += spi.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
+romstage-$(CONFIG_EARLY_CONSOLE) += uart.c
+romstage-y += wakeup.c
+romstage-y += pwm.c	# needed by timer.c
+romstage-y += gpio.c
+romstage-y += timer.c
+romstage-y += i2c.c
+#romstage-y += wdt.c
+
+ramstage-y += spi.c
+ramstage-y += clock.c
+ramstage-y += clock_init.c
+ramstage-y += pinmux.c
+ramstage-y += power.c
+ramstage-$(CONFIG_CONSOLE_SERIAL_UART) += uart.c
+ramstage-y += cpu.c
+ramstage-y += tmu.c
+ramstage-y += mct.c
+ramstage-y += monotonic_timer.c
+ramstage-y += pwm.c	# needed by timer.c
+ramstage-y += timer.c
+ramstage-y += gpio.c
+ramstage-y += i2c.c
+ramstage-y += dp-reg.c
+ramstage-y += fb.c
+
+exynos5420_add_bl1: $(obj)/coreboot.pre
+	printf "    DD         Adding Samsung Exynos5420 BL1\n"
+	dd if=3rdparty/cpu/samsung/exynos5420/E5420.nbl1.bin \
+		of=$(obj)/coreboot.pre conv=notrunc >/dev/null 2>&1
diff --git a/src/cpu/samsung/exynos5420/bootblock.c b/src/cpu/samsung/exynos5420/bootblock.c
new file mode 100644
index 0000000..f523428
--- /dev/null
+++ b/src/cpu/samsung/exynos5420/bootblock.c
@@ -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
+ */
+
+#include <console/console.h>
+#include "clk.h"
+#include "wakeup.h"
+
+void bootblock_cpu_init(void);
+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.
+	 */
+
+	console_init();
+}
diff --git a/src/cpu/samsung/exynos5420/chip.h b/src/cpu/samsung/exynos5420/chip.h
new file mode 100644
index 0000000..7f1aadc
--- /dev/null
+++ b/src/cpu/samsung/exynos5420/chip.h
@@ -0,0 +1,40 @@
+/*
+ * 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_EXYNOS5420_H
+#define CPU_SAMSUNG_EXYNOS5420_H
+
+struct cpu_samsung_exynos5420_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 bpp;
+
+	u32 lcdbase;
+};
+
+#endif /* CPU_SAMSUNG_EXYNOS5420_H */
diff --git a/src/cpu/samsung/exynos5420/clk.h b/src/cpu/samsung/exynos5420/clk.h
new file mode 100644
index 0000000..631b637
--- /dev/null
+++ b/src/cpu/samsung/exynos5420/clk.h
@@ -0,0 +1,624 @@
+/*
+ * 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_EXYNOS5420_CLK_H
+#define CPU_SAMSUNG_EXYNOS5420_CLK_H
+
+#include <stdint.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_ADDRESS 0x101c0000
+
+#define MCT_HZ 24000000
+
+/*
+ * Set mshci controller instances clock drivder
+ *
+ * @param enum periph_id instance of the mshci controller
+ *
+ * Return	0 if ok else -1
+ */
+int clock_set_mshci(enum periph_id peripheral);
+
+/*
+ * Sets the epll clockrate
+ *
+ * @param rate	Required clock rate to the presacaler in Hz
+ *
+ * Return	0 if ok else -1
+ */
+int clock_epll_set_rate(unsigned long rate);
+
+/*
+ * selects the clk source for I2S MCLK
+ */
+void clock_select_i2s_clk_source(void);
+
+/*
+ * Set prescaler division based on input and output frequency
+ * for i2s audio clock
+ *
+ * @param src_frq	Source frequency in Hz
+ * @param dst_frq	Required MCLK frequency in Hz
+ *
+ * Return	0 if ok else -1
+ */
+int clock_set_i2s_clk_prescaler(unsigned int src_frq, unsigned int dst_frq);
+
+struct exynos5_clock {
+	unsigned int	apll_lock;		/* base + 0 */
+	unsigned char	res1[0xfc];
+	unsigned int	apll_con0;
+	unsigned int	apll_con1;
+	unsigned char	res2[0xf8];
+	unsigned int	src_cpu;
+	unsigned char	res3[0x1fc];
+	unsigned int	mux_stat_cpu;
+	unsigned char	res4[0xfc];
+	unsigned int	div_cpu0;
+	unsigned int	div_cpu1;
+	unsigned char	res5[0xf8];
+	unsigned int	div_stat_cpu0;
+	unsigned int	div_stat_cpu1;
+	unsigned char	res6[0x1f8];
+	unsigned int	gate_sclk_cpu;
+	unsigned char	res7[0x1fc];
+	unsigned int	clkout_cmu_cpu;
+	unsigned int	clkout_cmu_cpu_div_stat;
+	unsigned char	res8[0x5f8];
+
+	unsigned int	armclk_stopctrl;	/* base + 0x1000 */
+	unsigned int	atclk_stopctrl;
+	unsigned char	res9[0x8];
+	unsigned int	parityfail_status;
+	unsigned int	parityfail_clear;
+	unsigned char	res10[0x8];
+	unsigned int	pwr_ctrl;
+	unsigned int	pwr_ctr2;
+	unsigned char	res11[0xd8];
+	unsigned int	apll_con0_l8;
+	unsigned int	apll_con0_l7;
+	unsigned int	apll_con0_l6;
+	unsigned int	apll_con0_l5;
+	unsigned int	apll_con0_l4;
+	unsigned int	apll_con0_l3;
+	unsigned int	apll_con0_l2;
+	unsigned int	apll_con0_l1;
+	unsigned int	iem_control;
+	unsigned char	res12[0xdc];
+	unsigned int	apll_con1_l8;
+	unsigned int	apll_con1_l7;
+	unsigned int	apll_con1_l6;
+	unsigned int	apll_con1_l5;
+	unsigned int	apll_con1_l4;
+	unsigned int	apll_con1_l3;
+	unsigned int	apll_con1_l2;
+	unsigned int	apll_con1_l1;
+	unsigned char	res13[0xe0];
+	unsigned int	div_iem_l8;
+	unsigned int	div_iem_l7;
+	unsigned int	div_iem_l6;
+	unsigned int	div_iem_l5;
+	unsigned int	div_iem_l4;
+	unsigned int	div_iem_l3;
+	unsigned int	div_iem_l2;
+	unsigned int	div_iem_l1;
+	unsigned char	res14[0x2ce0];
+
+	unsigned int	mpll_lock;		/* base + 0x4000 */
+	unsigned char	res15[0xfc];
+	unsigned int	mpll_con0;
+	unsigned int	mpll_con1;
+	unsigned char	res16[0xf8];
+	unsigned int	src_core0;
+	unsigned int	src_core1;
+	unsigned char	res17[0xf8];
+	unsigned int	src_mask_core;
+	unsigned char	res18[0x100];
+	unsigned int	mux_stat_core1;
+	unsigned char	res19[0xf8];
+	unsigned int	div_core0;
+	unsigned int	div_core1;
+	unsigned int	div_sysrgt;
+	unsigned char	res20[0xf4];
+	unsigned int	div_stat_core0;
+	unsigned int	div_stat_core1;
+	unsigned int	div_stat_sysrgt;
+	unsigned char	res21[0x2f4];
+	unsigned int	gate_ip_core;
+	unsigned int	gate_ip_sysrgt;
+	unsigned char	res22[0xf8];
+	unsigned int	clkout_cmu_core;
+	unsigned int	clkout_cmu_core_div_stat;
+	unsigned char	res23[0x5f8];
+
+	unsigned int	dcgidx_map0;		/* base + 0x5000 */
+	unsigned int	dcgidx_map1;
+	unsigned int	dcgidx_map2;
+	unsigned char	res24[0x14];
+	unsigned int	dcgperf_map0;
+	unsigned int	dcgperf_map1;
+	unsigned char	res25[0x18];
+	unsigned int	dvcidx_map;
+	unsigned char	res26[0x1c];
+	unsigned int	freq_cpu;
+	unsigned int	freq_dpm;
+	unsigned char	res27[0x18];
+	unsigned int	dvsemclk_en;
+	unsigned int	maxperf;
+	unsigned char	res28[0x3478];
+
+	unsigned int	div_acp;		/* base + 0x8500 */
+	unsigned char	res29[0xfc];
+	unsigned int	div_stat_acp;
+	unsigned char	res30[0x1fc];
+	unsigned int	gate_ip_acp;
+	unsigned char	res31a[0xfc];
+	unsigned int	div_syslft;
+	unsigned char	res31b[0xc];
+	unsigned int	div_stat_syslft;
+	unsigned char	res31c[0xc];
+	unsigned int	gate_bus_syslft;
+	unsigned char	res31d[0xdc];
+	unsigned int	clkout_cmu_acp;
+	unsigned int	clkout_cmu_acp_div_stat;
+	unsigned char	res32[0x38f8];
+
+	unsigned int	div_isp0;		/* base + 0xc300 */
+	unsigned int	div_isp1;
+	unsigned int	div_isp2;
+	unsigned char	res33[0xf4];
+
+	unsigned int	div_stat_isp0;		/* base + 0xc400 */
+	unsigned int	div_stat_isp1;
+	unsigned int	div_stat_isp2;
+	unsigned char	res34[0x3f4];
+
+	unsigned int	gate_ip_isp0;		/* base + 0xc800 */
+	unsigned int	gate_ip_isp1;
+	unsigned char	res35[0xf8];
+	unsigned int	gate_sclk_isp;
+	unsigned char	res36[0xc];
+	unsigned int	mcuisp_pwr_ctrl;
+	unsigned char	res37[0xec];
+	unsigned int	clkout_cmu_isp;
+	unsigned int	clkout_cmu_isp_div_stat;
+	unsigned char	res38[0x3618];
+
+	unsigned int	cpll_lock;		/* base + 0x10020 */
+	unsigned char	res39[0xc];
+	unsigned int	epll_lock;
+	unsigned char	res40[0xc];
+	unsigned int	vpll_lock;
+	unsigned char	res41a[0xc];
+	unsigned int	gpll_lock;
+	unsigned char	res41b[0xcc];
+	unsigned int	cpll_con0;
+	unsigned int	cpll_con1;
+	unsigned char	res42[0x8];
+	unsigned int	epll_con0;
+	unsigned int	epll_con1;
+	unsigned int	epll_con2;
+	unsigned char	res43[0x4];
+	unsigned int	vpll_con0;
+	unsigned int	vpll_con1;
+	unsigned int	vpll_con2;
+	unsigned char	res44a[0x4];
+	unsigned int	gpll_con0;
+	unsigned int	gpll_con1;
+	unsigned char	res44b[0xb8];
+	unsigned int	src_top0;
+	unsigned int	src_top1;
+	unsigned int	src_top2;
+	unsigned int	src_top3;
+	unsigned int	src_gscl;
+	unsigned int	src_disp0_0;
+	unsigned int	src_disp0_1;
+	unsigned int	src_disp1_0;
+	unsigned int	src_disp1_1;
+	unsigned char	res46[0xc];
+	unsigned int	src_mau;
+	unsigned int	src_fsys;
+	unsigned char	res47[0x8];
+	unsigned int	src_peric0;
+	unsigned int	src_peric1;
+	unsigned char	res48[0x18];
+	unsigned int	sclk_src_isp;
+	unsigned char	res49[0x9c];
+	unsigned int	src_mask_top;
+	unsigned char	res50[0xc];
+	unsigned int	src_mask_gscl;
+	unsigned int	src_mask_disp0_0;
+	unsigned int	src_mask_disp0_1;
+	unsigned int	src_mask_disp1_0;
+	unsigned int	src_mask_disp1_1;
+	unsigned int	src_mask_maudio;
+	unsigned char	res52[0x8];
+	unsigned int	src_mask_fsys;
+	unsigned char	res53[0xc];
+	unsigned int	src_mask_peric0;
+	unsigned int	src_mask_peric1;
+	unsigned char	res54[0x18];
+	unsigned int	src_mask_isp;
+	unsigned char	res55[0x9c];
+	unsigned int	mux_stat_top0;
+	unsigned int	mux_stat_top1;
+	unsigned int	mux_stat_top2;
+	unsigned int	mux_stat_top3;
+	unsigned char	res56[0xf0];
+	unsigned int	div_top0;
+	unsigned int	div_top1;
+	unsigned char	res57[0x8];
+	unsigned int	div_gscl;
+	unsigned int	div_disp0_0;
+	unsigned int	div_disp0_1;
+	unsigned int	div_disp1_0;
+	unsigned int	div_disp1_1;
+	unsigned char	res59[0x8];
+	unsigned int	div_gen;
+	unsigned char	res60[0x4];
+	unsigned int	div_mau;
+	unsigned int	div_fsys0;
+	unsigned int	div_fsys1;
+	unsigned int	div_fsys2;
+	unsigned int	div_fsys3;
+	unsigned int	div_peric0;
+	unsigned int	div_peric1;
+	unsigned int	div_peric2;
+	unsigned int	div_peric3;
+	unsigned int	div_peric4;
+	unsigned int	div_peric5;
+	unsigned char	res61[0x10];
+	unsigned int	sclk_div_isp;
+	unsigned char	res62[0xc];
+	unsigned int	div2_ratio0;
+	unsigned int	div2_ratio1;
+	unsigned char	res63[0x8];
+	unsigned int	div4_ratio;
+	unsigned char	res64[0x6c];
+	unsigned int	div_stat_top0;
+	unsigned int	div_stat_top1;
+	unsigned char	res65[0x8];
+	unsigned int	div_stat_gscl;
+	unsigned int	div_stat_disp0_0;
+	unsigned int	div_stat_disp0_1;
+	unsigned int	div_stat_disp1_0;
+	unsigned int	div_stat_disp1_1;
+	unsigned char	res67[0x8];
+	unsigned int	div_stat_gen;
+	unsigned char	res68[0x4];
+	unsigned int	div_stat_maudio;
+	unsigned int	div_stat_fsys0;
+	unsigned int	div_stat_fsys1;
+	unsigned int	div_stat_fsys2;
+	unsigned int	div_stat_fsys3;
+	unsigned int	div_stat_peric0;
+	unsigned int	div_stat_peric1;
+	unsigned int	div_stat_peric2;
+	unsigned int	div_stat_peric3;
+	unsigned int	div_stat_peric4;
+	unsigned int	div_stat_peric5;
+	unsigned char	res69[0x10];
+	unsigned int	sclk_div_stat_isp;
+	unsigned char	res70[0xc];
+	unsigned int	div2_stat0;
+	unsigned int	div2_stat1;
+	unsigned char	res71[0x8];
+	unsigned int	div4_stat;
+	unsigned char	res72[0x180];
+	unsigned int	gate_top_sclk_disp0;
+	unsigned int	gate_top_sclk_disp1;
+	unsigned int	gate_top_sclk_gen;
+	unsigned char	res74[0xc];
+	unsigned int	gate_top_sclk_mau;
+	unsigned int	gate_top_sclk_fsys;
+	unsigned char	res75[0xc];
+	unsigned int	gate_top_sclk_peric;
+	unsigned char	res76[0x1c];
+	unsigned int	gate_top_sclk_isp;
+	unsigned char	res77[0xac];
+	unsigned int	gate_ip_gscl;
+	unsigned int	gate_ip_disp0;
+	unsigned int	gate_ip_disp1;
+	unsigned int	gate_ip_mfc;
+	unsigned int	gate_ip_g3d;
+	unsigned int	gate_ip_gen;
+	unsigned char	res79[0xc];
+	unsigned int	gate_ip_fsys;
+	unsigned char	res80[0x4];
+	unsigned int	gate_ip_gps;
+	unsigned int	gate_ip_peric;
+	unsigned char	res81[0xc];
+	unsigned int	gate_ip_peris;
+	unsigned char	res82[0x1c];
+	unsigned int	gate_block;
+	unsigned char	res83[0x7c];
+	unsigned int	clkout_cmu_top;
+	unsigned int	clkout_cmu_top_div_stat;
+	unsigned char	res84[0x37f8];
+
+	unsigned int	src_lex;		/* base + 0x14200 */
+	unsigned char	res85[0x1fc];
+	unsigned int	mux_stat_lex;
+	unsigned char	res85b[0xfc];
+	unsigned int	div_lex;
+	unsigned char	res86[0xfc];
+	unsigned int	div_stat_lex;
+	unsigned char	res87[0x1fc];
+	unsigned int	gate_ip_lex;
+	unsigned char	res88[0x1fc];
+	unsigned int	clkout_cmu_lex;
+	unsigned int	clkout_cmu_lex_div_stat;
+	unsigned char	res89[0x3af8];
+
+	unsigned int	div_r0x;		/* base + 0x18500 */
+	unsigned char	res90[0xfc];
+	unsigned int	div_stat_r0x;
+	unsigned char	res91[0x1fc];
+	unsigned int	gate_ip_r0x;
+	unsigned char	res92[0x1fc];
+	unsigned int	clkout_cmu_r0x;
+	unsigned int	clkout_cmu_r0x_div_stat;
+	unsigned char	res94[0x3af8];
+
+	unsigned int	div_r1x;		/* base + 0x1c500 */
+	unsigned char	res95[0xfc];
+	unsigned int	div_stat_r1x;
+	unsigned char	res96[0x1fc];
+	unsigned int	gate_ip_r1x;
+	unsigned char	res97[0x1fc];
+	unsigned int	clkout_cmu_r1x;
+	unsigned int	clkout_cmu_r1x_div_stat;
+	unsigned char	res98[0x3608];
+
+	unsigned int	bpll_lock;		/* base + 0x2000c */
+	unsigned char	res99[0xfc];
+	unsigned int	bpll_con0;
+	unsigned int	bpll_con1;
+	unsigned char	res100[0xe8];
+	unsigned int	src_cdrex;
+	unsigned char	res101[0x1fc];
+	unsigned int	mux_stat_cdrex;
+	unsigned char	res102[0xfc];
+	unsigned int	div_cdrex;
+	unsigned int	div_cdrex2;
+	unsigned char	res103[0xf8];
+	unsigned int	div_stat_cdrex;
+	unsigned char	res104[0x2fc];
+	unsigned int	gate_ip_cdrex;
+	unsigned char	res105[0xc];
+	unsigned int	c2c_monitor;
+	unsigned int	dmc_pwr_ctrl;
+	unsigned char	res106[0x4];
+	unsigned int	drex2_pause;
+	unsigned char	res107[0xe0];
+	unsigned int	clkout_cmu_cdrex;
+	unsigned int	clkout_cmu_cdrex_div_stat;
+	unsigned char	res108[0x8];
+	unsigned int	lpddr3phy_ctrl;
+	unsigned char	res109a[0xc];
+	unsigned int	lpddr3phy_con3;
+	unsigned int	pll_div2_sel;
+	unsigned char	res109b[0xf5e4];
+};
+
+struct exynos5_mct_regs {
+	uint32_t	mct_cfg;
+	uint8_t		reserved0[0xfc];
+	uint32_t	g_cnt_l;
+	uint32_t	g_cnt_u;
+	uint8_t		reserved1[0x8];
+	uint32_t	g_cnt_wstat;
+	uint8_t		reserved2[0xec];
+	uint32_t	g_comp0_l;
+	uint32_t	g_comp0_u;
+	uint32_t	g_comp0_addr_incr;
+	uint8_t		reserved3[0x4];
+	uint32_t	g_comp1_l;
+	uint32_t	g_comp1_u;
+	uint32_t	g_comp1_addr_incr;
+	uint8_t		reserved4[0x4];
+	uint32_t	g_comp2_l;
+	uint32_t	g_comp2_u;
+	uint32_t	g_comp2_addr_incr;
+	uint8_t		reserved5[0x4];
+	uint32_t	g_comp3_l;
+	uint32_t	g_comp3_u;
+	uint32_t	g_comp3_addr_incr;
+	uint8_t		reserved6[0x4];
+	uint32_t	g_tcon;
+	uint32_t	g_int_cstat;
+	uint32_t	g_int_enb;
+	uint32_t	g_wstat;
+	uint8_t		reserved7[0xb0];
+	uint32_t	l0_tcntb;
+	uint32_t	l0_tcnto;
+	uint32_t	l0_icntb;
+	uint32_t	l0_icnto;
+	uint32_t	l0_frcntb;
+	uint32_t	l0_frcnto;
+	uint8_t		reserved8[0x8];
+	uint32_t	l0_tcon;
+	uint8_t		reserved9[0xc];
+	uint32_t	l0_int_cstat;
+	uint32_t	l0_int_enb;
+	uint8_t		reserved10[0x8];
+	uint32_t	l0_wstat;
+	uint8_t		reserved11[0xbc];
+	uint32_t	l1_tcntb;
+	uint32_t	l1_tcnto;
+	uint32_t	l1_icntb;
+	uint32_t	l1_icnto;
+	uint32_t	l1_frcntb;
+	uint32_t	l1_frcnto;
+	uint8_t		reserved12[0x8];
+	uint32_t	l1_tcon;
+	uint8_t		reserved13[0xc];
+	uint32_t	l1_int_cstat;
+	uint32_t	l1_int_enb;
+	uint8_t		reserved14[0x8];
+	uint32_t	l1_wstat;
+};
+
+#define EXYNOS5_EPLLCON0_LOCKED_SHIFT	29  /* EPLL Locked bit position*/
+#define EPLL_SRC_CLOCK			24000000  /*24 MHz Cristal Input */
+#define TIMEOUT_EPLL_LOCK		1000
+
+#define AUDIO_0_RATIO_MASK		0x0f
+#define AUDIO_1_RATIO_MASK		0x0f
+
+#define CLK_SRC_PERIC1			0x254
+#define AUDIO1_SEL_MASK			0xf
+#define CLK_SRC_AUDIOCDCLK1		0x0
+#define CLK_SRC_XXTI			0x1
+#define CLK_SRC_SCLK_EPLL		0x7
+
+/* CON0 bit-fields */
+#define EPLL_CON0_MDIV_MASK		0x1ff
+#define EPLL_CON0_PDIV_MASK		0x3f
+#define EPLL_CON0_SDIV_MASK		0x7
+#define EPLL_CON0_LOCKED_SHIFT		29
+#define EPLL_CON0_MDIV_SHIFT		16
+#define EPLL_CON0_PDIV_SHIFT		8
+#define EPLL_CON0_SDIV_SHIFT		0
+#define EPLL_CON0_LOCK_DET_EN_SHIFT	28
+#define EPLL_CON0_LOCK_DET_EN_MASK	1
+
+/* structure for epll configuration used in audio clock configuration */
+struct st_epll_con_val {
+	unsigned int freq_out;		/* frequency out */
+	unsigned int en_lock_det;	/* enable lock detect */
+	unsigned int m_div;		/* m divider value */
+	unsigned int p_div;		/* p divider value */
+	unsigned int s_div;		/* s divider value */
+	unsigned int k_dsm;		/* k value of delta signal modulator */
+};
+
+/**
+ * Low-level function to set the clock pre-ratio for a peripheral
+ *
+ * @param periph_id	Peripheral ID of peripheral to change
+ * @param divisor	New divisor for this peripheral's clock
+ */
+void clock_ll_set_pre_ratio(enum periph_id periph_id, unsigned divisor);
+
+/**
+ * Low-level function to set the clock ratio for a peripheral
+ *
+ * @param periph_id	Peripheral ID of peripheral to change
+ * @param divisor	New divisor for this peripheral's clock
+ */
+void clock_ll_set_ratio(enum periph_id periph_id, unsigned divisor);
+
+/**
+ * Low-level function that selects the best clock scalars for a given rate and
+ * sets up the given peripheral's clock accordingly.
+ *
+ * @param periph_id	Peripheral ID of peripheral to change
+ * @param rate		Desired clock rate in Hz
+ *
+ * @return zero on success, negative on error
+ */
+int clock_set_rate(enum periph_id periph_id, unsigned int rate);
+
+/* 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/cpu/samsung/exynos5420/clock.c b/src/cpu/samsung/exynos5420/clock.c
new file mode 100644
index 0000000..e199e6b
--- /dev/null
+++ b/src/cpu/samsung/exynos5420/clock.c
@@ -0,0 +1,691 @@
+/*
+ * 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 <console/console.h>
+#include <stdlib.h>
+#include <assert.h>
+#include <arch/io.h>
+#include "timer.h"
+#include "clk.h"
+#include "cpu.h"
+
+/* input clock of PLL: SMDK5420 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 achive different frequency output */
+static struct st_epll_con_val epll_div[] = {
+	{ 192000000, 0, 48, 3, 1, 0 },
+	{ 180000000, 0, 45, 3, 1, 0 },
+	{  73728000, 1, 73, 3, 3, 47710 },
+	{  67737600, 1, 90, 4, 3, 20762 },
+	{  49152000, 0, 49, 3, 3, 9961 },
+	{  45158400, 0, 45, 3, 3, 10381 },
+	{ 180633600, 0, 45, 3, 1, 10381 }
+};
+
+/* exynos5: return pll clock frequency */
+unsigned long get_pll_clk(int pllreg)
+{
+	struct exynos5_clock *clk =
+		samsung_get_base_clock();
+	unsigned long r, m, p, s, k = 0, mask, fout;
+	unsigned int freq;
+
+	switch (pllreg) {
+	case APLL:
+		r = readl(&clk->apll_con0);
+		break;
+	case BPLL:
+		r = readl(&clk->bpll_con0);
+		break;
+	case MPLL:
+		r = readl(&clk->mpll_con0);
+		break;
+	case EPLL:
+		r = readl(&clk->epll_con0);
+		k = readl(&clk->epll_con1);
+		break;
+	case VPLL:
+		r = readl(&clk->vpll_con0);
+		k = readl(&clk->vpll_con1);
+		break;
+	default:
+		printk(BIOS_DEBUG, "Unsupported PLL (%d)\n", pllreg);
+		return 0;
+	}
+
+	/*
+	 * APLL_CON: MIDV [25:16]
+	 * MPLL_CON: MIDV [25:16]
+	 * EPLL_CON: MIDV [24:16]
+	 * VPLL_CON: MIDV [24:16]
+	 */
+	if (pllreg == APLL || pllreg == BPLL || pllreg == MPLL)
+		mask = 0x3ff;
+	else
+		mask = 0x1ff;
+
+	m = (r >> 16) & mask;
+
+	/* PDIV [13:8] */
+	p = (r >> 8) & 0x3f;
+	/* SDIV [2:0] */
+	s = r & 0x7;
+
+	freq = CONFIG_SYS_CLK_FREQ;
+
+	if (pllreg == EPLL) {
+		k = k & 0xffff;
+		/* FOUT = (MDIV + K / 65536) * FIN / (PDIV * 2^SDIV) */
+		fout = (m + k / 65536) * (freq / (p * (1 << s)));
+	} else if (pllreg == VPLL) {
+		k = k & 0xfff;
+		/* FOUT = (MDIV + K / 1024) * FIN / (PDIV * 2^SDIV) */
+		fout = (m + k / 1024) * (freq / (p * (1 << s)));
+	} else {
+		/* FOUT = MDIV * FIN / (PDIV * 2^SDIV) */
+		fout = m * (freq / (p * (1 << s)));
+	}
+
+	return fout;
+}
+
+unsigned long clock_get_periph_rate(enum periph_id peripheral)
+{
+	struct exynos5_clock *clk =
+		samsung_get_base_clock();
+	struct clk_bit_info *bit_info = &clk_bit_info[peripheral];
+	unsigned long sclk, sub_clk;
+	unsigned int src, div, sub_div;
+
+	switch (peripheral) {
+	case PERIPH_ID_UART0:
+	case PERIPH_ID_UART1:
+	case PERIPH_ID_UART2:
+	case PERIPH_ID_UART3:
+		src = readl(&clk->src_peric0);
+		div = readl(&clk->div_peric0);
+		break;
+	case PERIPH_ID_PWM0:
+	case PERIPH_ID_PWM1:
+	case PERIPH_ID_PWM2:
+	case PERIPH_ID_PWM3:
+	case PERIPH_ID_PWM4:
+		src = readl(&clk->src_peric0);
+		div = readl(&clk->div_peric3);
+		break;
+	case PERIPH_ID_SPI0:
+	case PERIPH_ID_SPI1:
+		src = readl(&clk->src_peric1);
+		div = readl(&clk->div_peric1);
+		break;
+	case PERIPH_ID_SPI2:
+		src = readl(&clk->src_peric1);
+		div = readl(&clk->div_peric2);
+		break;
+	case PERIPH_ID_SPI3:
+	case PERIPH_ID_SPI4:
+		src = readl(&clk->sclk_src_isp);
+		div = readl(&clk->sclk_div_isp);
+		break;
+	case PERIPH_ID_SATA:
+		src = readl(&clk->src_fsys);
+		div = readl(&clk->div_fsys0);
+		break;
+	case PERIPH_ID_SDMMC0:
+	case PERIPH_ID_SDMMC1:
+	case PERIPH_ID_SDMMC2:
+	case PERIPH_ID_SDMMC3:
+		src = readl(&clk->src_fsys);
+		div = readl(&clk->div_fsys1);
+		break;
+	case PERIPH_ID_I2C0:
+	case PERIPH_ID_I2C1:
+	case PERIPH_ID_I2C2:
+	case PERIPH_ID_I2C3:
+	case PERIPH_ID_I2C4:
+	case PERIPH_ID_I2C5:
+	case PERIPH_ID_I2C6:
+	case PERIPH_ID_I2C7:
+		sclk = get_pll_clk(MPLL);
+		sub_div = ((readl(&clk->div_top1) >> bit_info->div_bit) & 0x7) + 1;
+		div = ((readl(&clk->div_top0) >> bit_info->prediv_bit) & 0x7) + 1;
+		return (sclk / sub_div) / div;
+	default:
+		printk(BIOS_DEBUG, "%s: invalid peripheral %d", __func__, peripheral);
+		return -1;
+	};
+
+	src = (src >> bit_info->src_bit) & ((1 << bit_info->n_src_bits) - 1);
+	if (peripheral == PERIPH_ID_SATA) {
+		if (src)
+			sclk = get_pll_clk(BPLL);
+		else
+			sclk = get_pll_clk(MPLL);
+	} else {
+		if (src == SRC_MPLL)
+			sclk = get_pll_clk(MPLL);
+		else if (src == SRC_EPLL)
+			sclk = get_pll_clk(EPLL);
+		else if (src == SRC_VPLL)
+			sclk = get_pll_clk(VPLL);
+		else
+			return 0;
+	}
+
+	sub_div = (div >> bit_info->div_bit) & 0xf;
+	sub_clk = sclk / (sub_div + 1);
+
+	if (peripheral == PERIPH_ID_SDMMC0 || peripheral == PERIPH_ID_SDMMC2) {
+		div = (div >> bit_info->prediv_bit) & 0xff;
+		return sub_clk / (div + 1);
+	}
+
+	return sub_clk;
+}
+
+/* exynos5: return ARM clock frequency */
+unsigned long get_arm_clk(void)
+{
+	struct exynos5_clock *clk =
+		samsung_get_base_clock();
+	unsigned long div;
+	unsigned long armclk;
+	unsigned int arm_ratio;
+	unsigned int arm2_ratio;
+
+	div = readl(&clk->div_cpu0);
+
+	/* ARM_RATIO: [2:0], ARM2_RATIO: [30:28] */
+	arm_ratio = (div >> 0) & 0x7;
+	arm2_ratio = (div >> 28) & 0x7;
+
+	armclk = get_pll_clk(APLL) / (arm_ratio + 1);
+	armclk /= (arm2_ratio + 1);
+
+	return armclk;
+}
+
+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)
+{
+	struct exynos5_clock *clk =
+		samsung_get_base_clock();
+	unsigned int *addr;
+	unsigned int val;
+
+	/*
+	 * CLK_DIV_FSYS1
+	 * MMC0_PRE_RATIO [15:8], MMC1_PRE_RATIO [31:24]
+	 * CLK_DIV_FSYS2
+	 * MMC2_PRE_RATIO [15:8], MMC3_PRE_RATIO [31:24]
+	 */
+	if (dev_index < 2) {
+		addr = &clk->div_fsys1;
+	} else {
+		addr = &clk->div_fsys2;
+		dev_index -= 2;
+	}
+
+	val = readl(addr);
+	val &= ~(0xff << ((dev_index << 4) + 8));
+	val |= (div & 0xff) << ((dev_index << 4) + 8);
+	writel(val, addr);
+}
+
+void clock_ll_set_pre_ratio(enum periph_id periph_id, unsigned divisor)
+{
+	struct exynos5_clock *clk =
+		samsung_get_base_clock();
+	unsigned shift;
+	unsigned mask = 0xff;
+	u32 *reg;
+
+	/*
+	 * For now we only handle a very small subset of peipherals here.
+	 * Others will need to (and do) mangle the clock registers
+	 * themselves, At some point it is hoped that this function can work
+	 * from a table or calculated register offset / mask. For now this
+	 * is at least better than spreading clock control code around
+	 * U-Boot.
+	 */
+	switch (periph_id) {
+	case PERIPH_ID_SPI0:
+		reg = &clk->div_peric1;
+		shift = 8;
+		break;
+	case PERIPH_ID_SPI1:
+		reg = &clk->div_peric1;
+		shift = 24;
+		break;
+	case PERIPH_ID_SPI2:
+		reg = &clk->div_peric2;
+		shift = 8;
+		break;
+	case PERIPH_ID_SPI3:
+		reg = &clk->sclk_div_isp;
+		shift = 4;
+		break;
+	case PERIPH_ID_SPI4:
+		reg = &clk->sclk_div_isp;
+		shift = 16;
+		break;
+	default:
+		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)
+{
+	struct exynos5_clock *clk =
+		samsung_get_base_clock();
+	unsigned shift;
+	unsigned mask = 0xff;
+	u32 *reg;
+
+	switch (periph_id) {
+	case PERIPH_ID_SPI0:
+		reg = &clk->div_peric1;
+		shift = 0;
+		break;
+	case PERIPH_ID_SPI1:
+		reg = &clk->div_peric1;
+		shift = 16;
+		break;
+	case PERIPH_ID_SPI2:
+		reg = &clk->div_peric2;
+		shift = 0;
+		break;
+	case PERIPH_ID_SPI3:
+		reg = &clk->sclk_div_isp;
+		shift = 0;
+		break;
+	case PERIPH_ID_SPI4:
+		reg = &clk->sclk_div_isp;
+		shift = 12;
+		break;
+	default:
+		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;
+	unsigned int fine;
+
+	switch (periph_id) {
+	case PERIPH_ID_SPI0:
+	case PERIPH_ID_SPI1:
+	case PERIPH_ID_SPI2:
+	case PERIPH_ID_SPI3:
+	case PERIPH_ID_SPI4:
+		main = clock_calc_best_scalar(4, 8, 400000000, rate, &fine);
+		if (main < 0) {
+			printk(BIOS_DEBUG, "%s: Cannot set clock rate for periph %d",
+					__func__, periph_id);
+			return -1;
+		}
+		clock_ll_set_ratio(periph_id, main - 1);
+		clock_ll_set_pre_ratio(periph_id, fine - 1);
+		break;
+	default:
+		printk(BIOS_DEBUG, "%s: Unsupported peripheral ID %d\n", __func__,
+		      periph_id);
+		return -1;
+	}
+
+	return 0;
+}
+
+int clock_set_mshci(enum periph_id peripheral)
+{
+	struct exynos5_clock *clk =
+		samsung_get_base_clock();
+	u32 *addr;
+	unsigned int clock;
+	unsigned int tmp;
+	unsigned int i;
+
+	/* get mpll clock */
+	clock = get_pll_clk(MPLL) / 1000000;
+
+	/*
+	 * CLK_DIV_FSYS1
+	 * MMC0_PRE_RATIO [15:8], MMC0_RATIO [3:0]
+	 * CLK_DIV_FSYS2
+	 * MMC2_PRE_RATIO [15:8], MMC2_RATIO [3:0]
+	 */
+	switch (peripheral) {
+	case PERIPH_ID_SDMMC0:
+		addr = &clk->div_fsys1;
+		break;
+	case PERIPH_ID_SDMMC2:
+		addr = &clk->div_fsys2;
+		break;
+	default:
+		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;
+	unsigned int start;
+	struct exynos5_clock *clk =
+		samsung_get_base_clock();
+
+	epll_con = readl(&clk->epll_con0);
+	epll_con &= ~((EPLL_CON0_LOCK_DET_EN_MASK <<
+			EPLL_CON0_LOCK_DET_EN_SHIFT) |
+		EPLL_CON0_MDIV_MASK << EPLL_CON0_MDIV_SHIFT |
+		EPLL_CON0_PDIV_MASK << EPLL_CON0_PDIV_SHIFT |
+		EPLL_CON0_SDIV_MASK << EPLL_CON0_SDIV_SHIFT);
+
+	for (i = 0; i < ARRAY_SIZE(epll_div); i++) {
+		if (epll_div[i].freq_out == rate)
+			break;
+	}
+
+	if (i == ARRAY_SIZE(epll_div))
+		return -1;
+
+	epll_con_k = epll_div[i].k_dsm << 0;
+	epll_con |= epll_div[i].en_lock_det << EPLL_CON0_LOCK_DET_EN_SHIFT;
+	epll_con |= epll_div[i].m_div << EPLL_CON0_MDIV_SHIFT;
+	epll_con |= epll_div[i].p_div << EPLL_CON0_PDIV_SHIFT;
+	epll_con |= epll_div[i].s_div << EPLL_CON0_SDIV_SHIFT;
+
+	/*
+	 * Required period ( in cycles) to genarate a stable clock output.
+	 * The maximum clock time can be up to 3000 * PDIV cycles of PLLs
+	 * frequency input (as per spec)
+	 */
+	lockcnt = 3000 * epll_div[i].p_div;
+
+	writel(lockcnt, &clk->epll_lock);
+	writel(epll_con, &clk->epll_con0);
+	writel(epll_con_k, &clk->epll_con1);
+
+	start = get_timer(0);
+
+	 while (!(readl(&clk->epll_con0) &
+			(0x1 << EXYNOS5_EPLLCON0_LOCKED_SHIFT))) {
+		if (get_timer(start) > TIMEOUT_EPLL_LOCK) {
+			printk(BIOS_DEBUG, "%s: Timeout waiting for EPLL lock\n", __func__);
+			return -1;
+		}
+	}
+
+	return 0;
+}
+
+void clock_select_i2s_clk_source(void)
+{
+	struct exynos5_clock *clk =
+		samsung_get_base_clock();
+
+	clrsetbits_le32(&clk->src_peric1, AUDIO1_SEL_MASK,
+			(CLK_SRC_SCLK_EPLL));
+}
+
+int clock_set_i2s_clk_prescaler(unsigned int src_frq, unsigned int dst_frq)
+{
+	struct exynos5_clock *clk =
+		samsung_get_base_clock();
+	unsigned int div ;
+
+	if ((dst_frq == 0) || (src_frq == 0)) {
+		printk(BIOS_DEBUG, "%s: Invalid requency 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(&clk->div_peric4, AUDIO_1_RATIO_MASK,
+				(div & AUDIO_1_RATIO_MASK));
+	return 0;
+}
diff --git a/src/cpu/samsung/exynos5420/clock_init.c b/src/cpu/samsung/exynos5420/clock_init.c
new file mode 100644
index 0000000..2986cab
--- /dev/null
+++ b/src/cpu/samsung/exynos5420/clock_init.c
@@ -0,0 +1,445 @@
+/*
+ * 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 SMDK5420 board based on EXYNOS5 */
+
+#include <console/console.h>
+#include <delay.h>
+#include "clk.h"
+#include "cpu.h"
+#include "dp.h"
+#include "setup.h"
+
+void system_clock_init(struct mem_timings *mem,
+		struct arm_clk_ratios *arm_clk_ratio)
+{
+	struct exynos5_clock *clk = (struct exynos5_clock *)EXYNOS5_CLOCK_BASE;
+	struct exynos5_mct_regs *mct_regs =
+		(struct exynos5_mct_regs *)EXYNOS5_MULTI_CORE_TIMER_BASE;
+	u32 val, tmp;
+
+	/* Turn on the MCT as early as possible. */
+	mct_regs->g_tcon |= (1 << 8);
+
+	clrbits_le32(&clk->src_cpu, MUX_APLL_SEL_MASK);
+	do {
+		val = readl(&clk->mux_stat_cpu);
+	} while ((val | MUX_APLL_SEL_MASK) != val);
+
+	clrbits_le32(&clk->src_core1, MUX_MPLL_SEL_MASK);
+	do {
+		val = readl(&clk->mux_stat_core1);
+	} while ((val | MUX_MPLL_SEL_MASK) != val);
+
+	clrbits_le32(&clk->src_top2, MUX_CPLL_SEL_MASK);
+	clrbits_le32(&clk->src_top2, MUX_EPLL_SEL_MASK);
+	clrbits_le32(&clk->src_top2, MUX_VPLL_SEL_MASK);
+	clrbits_le32(&clk->src_top2, MUX_GPLL_SEL_MASK);
+	tmp = MUX_CPLL_SEL_MASK | MUX_EPLL_SEL_MASK | MUX_VPLL_SEL_MASK
+		| MUX_GPLL_SEL_MASK;
+	do {
+		val = readl(&clk->mux_stat_top2);
+	} while ((val | tmp) != val);
+
+	clrbits_le32(&clk->src_cdrex, MUX_BPLL_SEL_MASK);
+	do {
+		val = readl(&clk->mux_stat_cdrex);
+	} while ((val | MUX_BPLL_SEL_MASK) != val);
+
+	/* PLL locktime */
+	writel(APLL_LOCK_VAL, &clk->apll_lock);
+
+	writel(MPLL_LOCK_VAL, &clk->mpll_lock);
+
+	writel(BPLL_LOCK_VAL, &clk->bpll_lock);
+
+	writel(CPLL_LOCK_VAL, &clk->cpll_lock);
+
+	writel(GPLL_LOCK_VAL, &clk->gpll_lock);
+
+	writel(EPLL_LOCK_VAL, &clk->epll_lock);
+
+	writel(VPLL_LOCK_VAL, &clk->vpll_lock);
+
+	writel(CLK_REG_DISABLE, &clk->pll_div2_sel);
+
+	writel(MUX_HPM_SEL_MASK, &clk->src_cpu);
+	do {
+		val = readl(&clk->mux_stat_cpu);
+	} while ((val | HPM_SEL_SCLK_MPLL) != val);
+
+	val = arm_clk_ratio->arm2_ratio << 28
+		| arm_clk_ratio->apll_ratio << 24
+		| arm_clk_ratio->pclk_dbg_ratio << 20
+		| arm_clk_ratio->atb_ratio << 16
+		| arm_clk_ratio->periph_ratio << 12
+		| arm_clk_ratio->acp_ratio << 8
+		| arm_clk_ratio->cpud_ratio << 4
+		| arm_clk_ratio->arm_ratio;
+	writel(val, &clk->div_cpu0);
+	do {
+		val = readl(&clk->div_stat_cpu0);
+	} while (0 != val);
+
+	writel(CLK_DIV_CPU1_VAL, &clk->div_cpu1);
+	do {
+		val = readl(&clk->div_stat_cpu1);
+	} while (0 != val);
+
+	/* Set APLL */
+	writel(APLL_CON1_VAL, &clk->apll_con1);
+	val = set_pll(arm_clk_ratio->apll_mdiv, arm_clk_ratio->apll_pdiv,
+			arm_clk_ratio->apll_sdiv);
+	writel(val, &clk->apll_con0);
+	while ((readl(&clk->apll_con0) & APLL_CON0_LOCKED) == 0)
+		;
+
+	/* Set MPLL */
+	writel(MPLL_CON1_VAL, &clk->mpll_con1);
+	val = set_pll(mem->mpll_mdiv, mem->mpll_pdiv, mem->mpll_sdiv);
+	writel(val, &clk->mpll_con0);
+	while ((readl(&clk->mpll_con0) & MPLL_CON0_LOCKED) == 0)
+		;
+
+	/*
+	 * Configure MUX_MPLL_FOUT to choose the direct clock source
+	 * path and avoid the fixed DIV/2 block to save power
+	 */
+	setbits_le32(&clk->pll_div2_sel, MUX_MPLL_FOUT_SEL);
+
+	/* Set BPLL */
+	if (mem->use_bpll) {
+		writel(BPLL_CON1_VAL, &clk->bpll_con1);
+		val = set_pll(mem->bpll_mdiv, mem->bpll_pdiv, mem->bpll_sdiv);
+		writel(val, &clk->bpll_con0);
+		while ((readl(&clk->bpll_con0) & BPLL_CON0_LOCKED) == 0)
+			;
+
+		setbits_le32(&clk->pll_div2_sel, MUX_BPLL_FOUT_SEL);
+	}
+
+	/* Set CPLL */
+	writel(CPLL_CON1_VAL, &clk->cpll_con1);
+	val = set_pll(mem->cpll_mdiv, mem->cpll_pdiv, mem->cpll_sdiv);
+	writel(val, &clk->cpll_con0);
+	while ((readl(&clk->cpll_con0) & CPLL_CON0_LOCKED) == 0)
+		;
+
+	/* Set GPLL */
+	writel(GPLL_CON1_VAL, &clk->gpll_con1);
+	val = set_pll(mem->gpll_mdiv, mem->gpll_pdiv, mem->gpll_sdiv);
+	writel(val, &clk->gpll_con0);
+	while ((readl(&clk->gpll_con0) & GPLL_CON0_LOCKED) == 0)
+		;
+
+	/* Set EPLL */
+	writel(EPLL_CON2_VAL, &clk->epll_con2);
+	writel(EPLL_CON1_VAL, &clk->epll_con1);
+	val = set_pll(mem->epll_mdiv, mem->epll_pdiv, mem->epll_sdiv);
+	writel(val, &clk->epll_con0);
+	while ((readl(&clk->epll_con0) & EPLL_CON0_LOCKED) == 0)
+		;
+
+	/* Set VPLL */
+	writel(VPLL_CON2_VAL, &clk->vpll_con2);
+	writel(VPLL_CON1_VAL, &clk->vpll_con1);
+	val = set_pll(mem->vpll_mdiv, mem->vpll_pdiv, mem->vpll_sdiv);
+	writel(val, &clk->vpll_con0);
+	while ((readl(&clk->vpll_con0) & VPLL_CON0_LOCKED) == 0)
+		;
+
+	writel(CLK_SRC_CORE0_VAL, &clk->src_core0);
+	writel(CLK_DIV_CORE0_VAL, &clk->div_core0);
+	while (readl(&clk->div_stat_core0) != 0)
+		;
+
+	writel(CLK_DIV_CORE1_VAL, &clk->div_core1);
+	while (readl(&clk->div_stat_core1) != 0)
+		;
+
+	writel(CLK_DIV_SYSRGT_VAL, &clk->div_sysrgt);
+	while (readl(&clk->div_stat_sysrgt) != 0)
+		;
+
+	writel(CLK_DIV_ACP_VAL, &clk->div_acp);
+	while (readl(&clk->div_stat_acp) != 0)
+		;
+
+	writel(CLK_DIV_SYSLFT_VAL, &clk->div_syslft);
+	while (readl(&clk->div_stat_syslft) != 0)
+		;
+
+	writel(CLK_SRC_TOP0_VAL, &clk->src_top0);
+	writel(CLK_SRC_TOP1_VAL, &clk->src_top1);
+	writel(TOP2_VAL, &clk->src_top2);
+	writel(CLK_SRC_TOP3_VAL, &clk->src_top3);
+
+	writel(CLK_DIV_TOP0_VAL, &clk->div_top0);
+	while (readl(&clk->div_stat_top0))
+		;
+
+	writel(CLK_DIV_TOP1_VAL, &clk->div_top1);
+	while (readl(&clk->div_stat_top1))
+		;
+
+	writel(CLK_SRC_LEX_VAL, &clk->src_lex);
+	while (1) {
+		val = readl(&clk->mux_stat_lex);
+		if (val == (val | 1))
+			break;
+	}
+
+	writel(CLK_DIV_LEX_VAL, &clk->div_lex);
+	while (readl(&clk->div_stat_lex))
+		;
+
+	writel(CLK_DIV_R0X_VAL, &clk->div_r0x);
+	while (readl(&clk->div_stat_r0x))
+		;
+
+	writel(CLK_DIV_R0X_VAL, &clk->div_r0x);
+	while (readl(&clk->div_stat_r0x))
+		;
+
+	writel(CLK_DIV_R1X_VAL, &clk->div_r1x);
+	while (readl(&clk->div_stat_r1x))
+		;
+
+	if (mem->use_bpll) {
+		writel(MUX_BPLL_SEL_MASK | MUX_MCLK_CDREX_SEL |
+			MUX_MCLK_DPHY_SEL, &clk->src_cdrex);
+	} else {
+		writel(CLK_REG_DISABLE, &clk->src_cdrex);
+	}
+
+	writel(CLK_DIV_CDREX_VAL, &clk->div_cdrex);
+	while (readl(&clk->div_stat_cdrex))
+		;
+
+	val = readl(&clk->src_cpu);
+	val |= CLK_SRC_CPU_VAL;
+	writel(val, &clk->src_cpu);
+
+	val = readl(&clk->src_top2);
+	val |= CLK_SRC_TOP2_VAL;
+	writel(val, &clk->src_top2);
+
+	val = readl(&clk->src_core1);
+	val |= CLK_SRC_CORE1_VAL;
+	writel(val, &clk->src_core1);
+
+	writel(CLK_SRC_FSYS0_VAL, &clk->src_fsys);
+	writel(CLK_DIV_FSYS0_VAL, &clk->div_fsys0);
+	while (readl(&clk->div_stat_fsys0))
+		;
+
+	writel(CLK_REG_DISABLE, &clk->clkout_cmu_cpu);
+	writel(CLK_REG_DISABLE, &clk->clkout_cmu_core);
+	writel(CLK_REG_DISABLE, &clk->clkout_cmu_acp);
+	writel(CLK_REG_DISABLE, &clk->clkout_cmu_top);
+	writel(CLK_REG_DISABLE, &clk->clkout_cmu_lex);
+	writel(CLK_REG_DISABLE, &clk->clkout_cmu_r0x);
+	writel(CLK_REG_DISABLE, &clk->clkout_cmu_r1x);
+	writel(CLK_REG_DISABLE, &clk->clkout_cmu_cdrex);
+
+	writel(CLK_SRC_PERIC0_VAL, &clk->src_peric0);
+	writel(CLK_DIV_PERIC0_VAL, &clk->div_peric0);
+
+	writel(CLK_SRC_PERIC1_VAL, &clk->src_peric1);
+	writel(CLK_DIV_PERIC1_VAL, &clk->div_peric1);
+	writel(CLK_DIV_PERIC2_VAL, &clk->div_peric2);
+	writel(SCLK_SRC_ISP_VAL, &clk->sclk_src_isp);
+	writel(SCLK_DIV_ISP_VAL, &clk->sclk_div_isp);
+	writel(CLK_DIV_ISP0_VAL, &clk->div_isp0);
+	writel(CLK_DIV_ISP1_VAL, &clk->div_isp1);
+	writel(CLK_DIV_ISP2_VAL, &clk->div_isp2);
+
+	/* FIMD1 SRC CLK SELECTION */
+	writel(CLK_SRC_DISP1_0_VAL, &clk->src_disp1_0);
+
+	val = MMC2_PRE_RATIO_VAL << MMC2_PRE_RATIO_OFFSET
+		| MMC2_RATIO_VAL << MMC2_RATIO_OFFSET
+		| MMC3_PRE_RATIO_VAL << MMC3_PRE_RATIO_OFFSET
+		| MMC3_RATIO_VAL << MMC3_RATIO_OFFSET;
+	writel(val, &clk->div_fsys2);
+}
+
+void clock_gate(void)
+{
+	struct exynos5_clock *clk = (struct exynos5_clock *)EXYNOS5_CLOCK_BASE;
+
+	/* CLK_GATE_IP_SYSRGT */
+	clrbits_le32(&clk->gate_ip_sysrgt, CLK_C2C_MASK);
+
+	/* CLK_GATE_IP_ACP */
+	clrbits_le32(&clk->gate_ip_acp, CLK_SMMUG2D_MASK |
+					CLK_SMMUSSS_MASK |
+					CLK_SMMUMDMA_MASK |
+					CLK_ID_REMAPPER_MASK |
+					CLK_G2D_MASK |
+					CLK_SSS_MASK |
+					CLK_MDMA_MASK |
+					CLK_SECJTAG_MASK);
+
+	/* CLK_GATE_BUS_SYSLFT */
+	clrbits_le32(&clk->gate_bus_syslft, CLK_EFCLK_MASK);
+
+	/* CLK_GATE_IP_ISP0 */
+	clrbits_le32(&clk->gate_ip_isp0, CLK_UART_ISP_MASK |
+					 CLK_WDT_ISP_MASK |
+					 CLK_PWM_ISP_MASK |
+					 CLK_MTCADC_ISP_MASK |
+					 CLK_I2C1_ISP_MASK |
+					 CLK_I2C0_ISP_MASK |
+					 CLK_MPWM_ISP_MASK |
+					 CLK_MCUCTL_ISP_MASK |
+					 CLK_INT_COMB_ISP_MASK |
+					 CLK_SMMU_MCUISP_MASK |
+					 CLK_SMMU_SCALERP_MASK |
+					 CLK_SMMU_SCALERC_MASK |
+					 CLK_SMMU_FD_MASK |
+					 CLK_SMMU_DRC_MASK |
+					 CLK_SMMU_ISP_MASK |
+					 CLK_GICISP_MASK |
+					 CLK_ARM9S_MASK |
+					 CLK_MCUISP_MASK |
+					 CLK_SCALERP_MASK |
+					 CLK_SCALERC_MASK |
+					 CLK_FD_MASK |
+					 CLK_DRC_MASK |
+					 CLK_ISP_MASK);
+
+	/* CLK_GATE_IP_ISP1 */
+	clrbits_le32(&clk->gate_ip_isp1, CLK_SPI1_ISP_MASK |
+					 CLK_SPI0_ISP_MASK |
+					 CLK_SMMU3DNR_MASK |
+					 CLK_SMMUDIS1_MASK |
+					 CLK_SMMUDIS0_MASK |
+					 CLK_SMMUODC_MASK |
+					 CLK_3DNR_MASK |
+					 CLK_DIS_MASK |
+					 CLK_ODC_MASK);
+
+	/* CLK_GATE_SCLK_ISP */
+	clrbits_le32(&clk->gate_sclk_isp, SCLK_MPWM_ISP_MASK);
+
+	/* CLK_GATE_IP_GSCL */
+	clrbits_le32(&clk->gate_ip_gscl, CLK_SMMUFIMC_LITE2_MASK |
+					 CLK_SMMUFIMC_LITE1_MASK |
+					 CLK_SMMUFIMC_LITE0_MASK |
+					 CLK_SMMUGSCL3_MASK |
+					 CLK_SMMUGSCL2_MASK |
+					 CLK_SMMUGSCL1_MASK |
+					 CLK_SMMUGSCL0_MASK |
+					 CLK_GSCL_WRAP_B_MASK |
+					 CLK_GSCL_WRAP_A_MASK |
+					 CLK_CAMIF_TOP_MASK |
+					 CLK_GSCL3_MASK |
+					 CLK_GSCL2_MASK |
+					 CLK_GSCL1_MASK |
+					 CLK_GSCL0_MASK);
+
+	/* CLK_GATE_IP_DISP1 */
+	clrbits_le32(&clk->gate_ip_disp1, CLK_SMMUTVX_MASK |
+					  CLK_ASYNCTVX_MASK |
+					  CLK_HDMI_MASK |
+					  CLK_MIXER_MASK |
+					  CLK_DSIM1_MASK);
+
+	/* CLK_GATE_IP_MFC */
+	clrbits_le32(&clk->gate_ip_mfc, CLK_SMMUMFCR_MASK |
+					CLK_SMMUMFCL_MASK |
+					CLK_MFC_MASK);
+
+	/* CLK_GATE_IP_GEN */
+	clrbits_le32(&clk->gate_ip_gen, CLK_SMMUMDMA1_MASK |
+					CLK_SMMUJPEG_MASK |
+					CLK_SMMUROTATOR_MASK |
+					CLK_MDMA1_MASK |
+					CLK_JPEG_MASK |
+					CLK_ROTATOR_MASK);
+
+	/* CLK_GATE_IP_FSYS */
+	clrbits_le32(&clk->gate_ip_fsys, CLK_WDT_IOP_MASK |
+					 CLK_SMMUMCU_IOP_MASK |
+					 CLK_SATA_PHY_I2C_MASK |
+					 CLK_SATA_PHY_CTRL_MASK |
+					 CLK_MCUCTL_MASK |
+					 CLK_NFCON_MASK |
+					 CLK_SMMURTIC_MASK |
+					 CLK_RTIC_MASK |
+					 CLK_MIPI_HSI_MASK |
+					 CLK_USBOTG_MASK |
+					 CLK_SATA_MASK |
+					 CLK_PDMA1_MASK |
+					 CLK_PDMA0_MASK |
+					 CLK_MCU_IOP_MASK);
+
+	/* CLK_GATE_IP_PERIC */
+	clrbits_le32(&clk->gate_ip_peric, CLK_HS_I2C3_MASK |
+					  CLK_HS_I2C2_MASK |
+					  CLK_HS_I2C1_MASK |
+					  CLK_HS_I2C0_MASK |
+					  CLK_AC97_MASK |
+					  CLK_SPDIF_MASK |
+					  CLK_PCM2_MASK |
+					  CLK_PCM1_MASK |
+					  CLK_I2S2_MASK |
+					  CLK_SPI2_MASK |
+					  CLK_SPI0_MASK);
+
+	/*
+	 * CLK_GATE_IP_PERIS
+	 * 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(&clk->gate_ip_peris, CLK_RTC_MASK |
+					  CLK_TZPC9_MASK |
+					  CLK_TZPC8_MASK |
+					  CLK_TZPC7_MASK |
+					  CLK_TZPC6_MASK |
+					  CLK_TZPC5_MASK |
+					  CLK_TZPC4_MASK |
+					  CLK_TZPC3_MASK |
+					  CLK_TZPC2_MASK |
+					  CLK_TZPC1_MASK |
+					  CLK_TZPC0_MASK);
+
+	/* CLK_GATE_BLOCK */
+	clrbits_le32(&clk->gate_block, CLK_ACP_MASK);
+
+	/* CLK_GATE_IP_CDREX */
+	clrbits_le32(&clk->gate_ip_cdrex, CLK_DPHY0_MASK |
+					  CLK_DPHY1_MASK |
+					  CLK_TZASC_DRBXR_MASK);
+
+}
+
+void clock_init_dp_clock(void)
+{
+	struct exynos5_clock *clk = (struct exynos5_clock *)EXYNOS5_CLOCK_BASE;
+
+	/* DP clock enable */
+	setbits_le32(&clk->gate_ip_disp1, CLK_GATE_DP1_ALLOW);
+
+	/* We run DP at 267 Mhz */
+	setbits_le32(&clk->div_disp1_0, CLK_DIV_DISP1_0_FIMD1);
+}
+
diff --git a/src/cpu/samsung/exynos5420/cpu.c b/src/cpu/samsung/exynos5420/cpu.c
new file mode 100644
index 0000000..0abc0a3
--- /dev/null
+++ b/src/cpu/samsung/exynos5420/cpu.c
@@ -0,0 +1,181 @@
+/*
+ * 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 <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"
+
+#define RAM_BASE_KB (CONFIG_SYS_SDRAM_BASE >> 10)
+#define RAM_SIZE_KB (CONFIG_DRAM_SIZE_MB << 10UL)
+
+static unsigned int cpu_id;
+static unsigned int cpu_rev;
+
+static void set_cpu_id(void)
+{
+	cpu_id = readl((void *)EXYNOS_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)
+{
+	int ret;
+	struct cpu_samsung_exynos5420_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.
+	 */
+	vidinfo_t vi;
+	struct exynos5_fimd_panel panel;
+	unsigned long int fb_size;
+	u32 lcdbase;
+
+	memset(&vi, 0, sizeof(vi));
+	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;
+
+	vi.vl_col = conf->xres;
+	vi.vl_row = conf->yres;
+	vi.vl_bpix = conf->bpp;
+	/*
+	 * The size is a magic number from hardware. Allocate enough for the
+	 * frame buffer and color map.
+	 */
+	fb_size = conf->xres * conf->yres * (conf->bpp / 8);
+	lcdbase = (uintptr_t)cbmem_add(CBMEM_ID_CONSOLE, fb_size + 64*KiB);
+	printk(BIOS_SPEW, "LCD colormap base is %p\n", (void *)(lcdbase));
+	mmio_resource(dev, 0, lcdbase/KiB, 64);
+	vi.cmap = (void *)lcdbase;
+
+	/*
+	 * 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 inadvertantly.
+	 *
+	 * FIXME: Is disabling/re-enabling the MMU entirely necessary?
+	 */
+	uint32_t lower = ALIGN_DOWN(lcdbase, MiB);
+	uint32_t upper = ALIGN_UP(lcdbase + fb_size + 64*KiB, MiB);
+	dcache_clean_invalidate_by_mva(lower, upper - lower);
+	dcache_mmu_disable();
+	mmu_config_range(lower/MiB, (upper - lower)/MiB, DCACHE_OFF);
+	dcache_mmu_enable();
+
+	lcdbase += 64*KiB;
+	mmio_resource(dev, 1, lcdbase/KiB, (fb_size + KiB - 1)/KiB);
+	printk(BIOS_DEBUG,
+	       "Initializing Exynos VGA, base %p\n", (void *)lcdbase);
+	memset((void *)lcdbase, 0, fb_size);	/* clear the framebuffer */
+	ret = lcd_ctrl_init(&vi, &panel, (void *)lcdbase);
+}
+
+static void cpu_init(device_t dev)
+{
+	exynos_displayport_init(dev);
+	ram_resource(dev, 0, RAM_BASE_KB, RAM_SIZE_KB);
+
+	set_cpu_id();
+
+	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_init,
+	.init             = cpu_noop,
+	.scan_bus         = 0,
+};
+
+static void enable_exynos5420_dev(device_t dev)
+{
+	dev->ops = &cpu_ops;
+}
+
+struct chip_operations cpu_samsung_exynos5420_ops = {
+	CHIP_NAME("CPU Samsung Exynos 5420")
+	.enable_dev = enable_exynos5420_dev,
+};
+
+void exynos5420_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/cpu/samsung/exynos5420/cpu.h b/src/cpu/samsung/exynos5420/cpu.h
new file mode 100644
index 0000000..62ff424
--- /dev/null
+++ b/src/cpu/samsung/exynos5420/cpu.h
@@ -0,0 +1,130 @@
+/*
+ * 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_EXYNOS5420_CPU_H
+#define CPU_SAMSUNG_EXYNOS5420_CPU_H
+
+#include <arch/io.h>
+
+#define DEVICE_NOT_AVAILABLE		0
+
+#define EXYNOS_PRO_ID			0x10000000
+
+/* Address of address of function that copys data from SD or MMC */
+#define EXYNOS_COPY_MMC_FNPTR_ADDR	0x02020030
+
+/* Address of address of function that copys data from SPI */
+#define EXYNOS_COPY_SPI_FNPTR_ADDR	0x02020058
+
+/* Address of address of function that copys data through USB */
+#define EXYNOS_COPY_USB_FNPTR_ADDR	0x02020070
+
+/* Boot mode values */
+#define EXYNOS_USB_SECONDARY_BOOT	0xfeed0002
+
+#define EXYNOS_IRAM_SECONDARY_BASE	0x02020018
+
+#define EXYNOS_I2C_SPACING		0x10000
+
+/* EXYNOS5 */
+#define EXYNOS5_GPIO_PART6_BASE		0x03860000	/* Z<6:0> */
+#define EXYNOS5_PRO_ID			0x10000000
+#define EXYNOS5_CLOCK_BASE		0x10010000
+#define EXYNOS5_POWER_BASE		0x10040000
+#define EXYNOS5_SWRESET			0x10040400
+#define EXYNOS5_SYSREG_BASE		0x10050000
+#define EXYNOS5_TZPC1_DECPROT1SET	0x10110810
+#define EXYNOS5_MULTI_CORE_TIMER_BASE	0x101C0000
+#define EXYNOS5_WATCHDOG_BASE		0x101D0000
+#define EXYNOS5_ACE_SFR_BASE            0x10830000
+#define EXYNOS5_DMC_PHY0_BASE		0x10C00000
+#define EXYNOS5_DMC_PHY1_BASE		0x10C10000
+#define EXYNOS5_GPIO_PART4_BASE		0x10D10000	/* V00..V37 */
+#define EXYNOS5_GPIO_PART5_BASE		0x10D100C0	/* V40..V47 */
+#define EXYNOS5_DMC_CTRL_BASE		0x10DD0000
+#define EXYNOS5_GPIO_PART1_BASE		0x11400000	/* A00..Y67 */
+#define EXYNOS5_GPIO_PART2_BASE		0x11400c00	/* X00..X37 */
+#define EXYNOS5_USB_HOST_EHCI_BASE	0x12110000
+#define EXYNOS5_USBPHY_BASE		0x12130000
+#define EXYNOS5_USBOTG_BASE		0x12140000
+
+#define EXYNOS5_MMC_BASE		0x12200000
+#define EXYNOS5_MSHC_BASE		0x12240000
+
+#define EXYNOS5_SROMC_BASE		0x12250000
+#define EXYNOS5_UART_BASE		0x12C00000
+
+#define EXYNOS5_SPI1_BASE		0x12D30000
+#define EXYNOS5_I2C_BASE		0x12C60000
+#define EXYNOS5_SPI_BASE		0x12D20000
+#define EXYNOS5_PWMTIMER_BASE		0x12DD0000
+#define EXYNOS5_SPI_ISP_BASE		0x131A0000
+#define EXYNOS5_I2S_BASE		0x12D60000
+#define EXYNOS5_GPIO_PART3_BASE		0x13400000	/* E00..H17 */
+#define EXYNOS5_FIMD_BASE		0x14400000
+#define EXYNOS5_DISP1_CTRL_BASE		0x14420000
+#define EXYNOS5_MIPI_DSI1_BASE		0x14500000
+
+#define EXYNOS5_ADC_BASE		DEVICE_NOT_AVAILABLE
+#define EXYNOS5_MODEM_BASE		DEVICE_NOT_AVAILABLE
+
+/* Compatibility defines */
+#define EXYNOS_POWER_BASE		EXYNOS5_POWER_BASE
+
+/* Marker values stored at the bottom of IRAM stack by SPL */
+#define EXYNOS5_SPL_MARKER	0xb004f1a9	/* hexspeak word: bootflag */
+
+/* Distance between each Trust Zone PC register set */
+#define TZPC_BASE_OFFSET		0x10000
+
+#define samsung_get_base_adc() ((struct exynos5_adc *)EXYNOS5_ADC_BASE)
+#define samsung_get_base_clock() ((struct exynos5_clock *)EXYNOS5_CLOCK_BASE)
+#define samsung_get_base_ace_sfr() ((struct exynos5_ace_sfr *)EXYNOS5_ACE_SFR_BASE)
+#define samsung_get_base_dsim() ((struct exynos5_dsim *)EXYNOS5_MIPI_DSI1_BASE)
+#define samsung_get_base_disp_ctrl() ((struct exynos5_disp_ctrl *)EXYNOS5_DISP1_CTRL_BASE)
+#define samsung_get_base_fimd() ((struct exynos5_fimd *)EXYNOS5_FIMD_BASE)
+#define samsung_get_base_pro_id() ((struct exynos5_pro_id *)EXYNOS5_PRO_ID)
+
+#define samsung_get_base_mmc() ((struct exynos5_mmc *)EXYNOS5_MMC_BASE)
+#define samsung_get_base_mshci() ((struct exynos5_mshci *)EXYNOS5_MSHC_BASE)
+
+#define samsung_get_base_modem() ((struct exynos5_modem *)EXYNOS5_MODEM_BASE)
+#define samsung_get_base_sromc() ((struct exynos5_sromc *)EXYNOS5_SROMC_BASE)
+#define samsung_get_base_swreset() ((struct exynos5_swreset *)EXYNOS5_SWRESET)
+#define samsung_get_base_sysreg() ((struct exynos5_sysreg *)EXYNOS5_SYSREG_BASE)
+#define samsung_get_base_timer() ((struct s5p_timer *)EXYNOS5_PWMTIMER_BASE)
+#define samsung_get_base_uart() ((struct exynos5_uart *)EXYNOS5_UART_BASE)
+#define samsung_get_base_usb_phy() ((struct exynos5_usb_phy *)EXYNOS5_USBPHY_BASE)
+#define samsung_get_base_usb_otg() ((struct exynos5_usb_otg *)EXYNOS5_USBOTG_BASE)
+#define samsung_get_base_watchdog() ((struct exynos5_watchdog *)EXYNOS5_WATCHDOG_BASE)
+#define samsung_get_base_power() ((struct exynos5_power *)EXYNOS5_POWER_BASE)
+#define samsung_get_base_i2s() ((struct exynos5_i2s *)EXYNOS5_I2S_BASE)
+#define samsung_get_base_spi1() ((struct exynos5_spi1 *)EXYNOS5_SPI1_BASE)
+#define samsung_get_base_i2c() ((struct exynos5_i2c *)EXYNOS5_I2C_BASE)
+#define samsung_get_base_spi() ((struct exynos5_spi *)EXYNOS5_SPI_BASE)
+#define samsung_get_base_spi_isp() ((struct exynos5_spi_isp *)EXYNOS5_SPI_ISP_BASE)
+
+#define EXYNOS5_SPI_NUM_CONTROLLERS	5
+#define EXYNOS_I2C_MAX_CONTROLLERS	8
+
+void exynos5420_config_l2_cache(void);
+
+extern struct tmu_info exynos5420_tmu_info;
+
+#endif	/* _EXYNOS5420_CPU_H */
diff --git a/src/cpu/samsung/exynos5420/dmc.h b/src/cpu/samsung/exynos5420/dmc.h
new file mode 100644
index 0000000..cd5ff23
--- /dev/null
+++ b/src/cpu/samsung/exynos5420/dmc.h
@@ -0,0 +1,343 @@
+/*
+ * 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_EXYNOS5420_DMC_H
+#define CPU_SAMSUNG_EXYNOS5420_DMC_H
+
+#ifndef __ASSEMBLER__
+struct exynos5_dmc {
+	unsigned int concontrol;
+	unsigned int memcontrol;
+	unsigned int memconfig0;
+	unsigned int memconfig1;
+	unsigned int directcmd;
+	unsigned int prechconfig;
+	unsigned int phycontrol0;
+	unsigned char res1[0xc];
+	unsigned int pwrdnconfig;
+	unsigned int timingpzq;
+	unsigned int timingref;
+	unsigned int timingrow;
+	unsigned int timingdata;
+	unsigned int timingpower;
+	unsigned int phystatus;
+	unsigned char res2[0x4];
+	unsigned int chipstatus_ch0;
+	unsigned int chipstatus_ch1;
+	unsigned char res3[0x4];
+	unsigned int mrstatus;
+	unsigned char res4[0x8];
+	unsigned int qoscontrol0;
+	unsigned char resr5[0x4];
+	unsigned int qoscontrol1;
+	unsigned char res6[0x4];
+	unsigned int qoscontrol2;
+	unsigned char res7[0x4];
+	unsigned int qoscontrol3;
+	unsigned char res8[0x4];
+	unsigned int qoscontrol4;
+	unsigned char res9[0x4];
+	unsigned int qoscontrol5;
+	unsigned char res10[0x4];
+	unsigned int qoscontrol6;
+	unsigned char res11[0x4];
+	unsigned int qoscontrol7;
+	unsigned char res12[0x4];
+	unsigned int qoscontrol8;
+	unsigned char res13[0x4];
+	unsigned int qoscontrol9;
+	unsigned char res14[0x4];
+	unsigned int qoscontrol10;
+	unsigned char res15[0x4];
+	unsigned int qoscontrol11;
+	unsigned char res16[0x4];
+	unsigned int qoscontrol12;
+	unsigned char res17[0x4];
+	unsigned int qoscontrol13;
+	unsigned char res18[0x4];
+	unsigned int qoscontrol14;
+	unsigned char res19[0x4];
+	unsigned int qoscontrol15;
+	unsigned char res20[0x14];
+	unsigned int ivcontrol;
+	unsigned int wrtra_config;
+	unsigned int rdlvl_config;
+	unsigned char res21[0x8];
+	unsigned int brbrsvconfig;
+	unsigned int brbqosconfig;
+	unsigned int membaseconfig0;
+	unsigned int membaseconfig1;
+	unsigned char res22[0xc];
+	unsigned int wrlvl_config;
+	unsigned char res23[0xc];
+	unsigned int perevcontrol;
+	unsigned int perev0config;
+	unsigned int perev1config;
+	unsigned int perev2config;
+	unsigned int perev3config;
+	unsigned char res24[0xdebc];
+	unsigned int pmnc_ppc_a;
+	unsigned char res25[0xc];
+	unsigned int cntens_ppc_a;
+	unsigned char res26[0xc];
+	unsigned int cntenc_ppc_a;
+	unsigned char res27[0xc];
+	unsigned int intens_ppc_a;
+	unsigned char res28[0xc];
+	unsigned int intenc_ppc_a;
+	unsigned char res29[0xc];
+	unsigned int flag_ppc_a;
+	unsigned char res30[0xac];
+	unsigned int ccnt_ppc_a;
+	unsigned char res31[0xc];
+	unsigned int pmcnt0_ppc_a;
+	unsigned char res32[0xc];
+	unsigned int pmcnt1_ppc_a;
+	unsigned char res33[0xc];
+	unsigned int pmcnt2_ppc_a;
+	unsigned char res34[0xc];
+	unsigned int pmcnt3_ppc_a;
+};
+
+struct exynos5_phy_control {
+	unsigned int phy_con0;
+	unsigned int phy_con1;
+	unsigned int phy_con2;
+	unsigned int phy_con3;
+	unsigned int phy_con4;
+	unsigned char res1[4];
+	unsigned int phy_con6;
+	unsigned char res2[4];
+	unsigned int phy_con8;
+	unsigned int phy_con9;
+	unsigned int phy_con10;
+	unsigned char res3[4];
+	unsigned int phy_con12;
+	unsigned int phy_con13;
+	unsigned int phy_con14;
+	unsigned int phy_con15;
+	unsigned int phy_con16;
+	unsigned char res4[4];
+	unsigned int phy_con17;
+	unsigned int phy_con18;
+	unsigned int phy_con19;
+	unsigned int phy_con20;
+	unsigned int phy_con21;
+	unsigned int phy_con22;
+	unsigned int phy_con23;
+	unsigned int phy_con24;
+	unsigned int phy_con25;
+	unsigned int phy_con26;
+	unsigned int phy_con27;
+	unsigned int phy_con28;
+	unsigned int phy_con29;
+	unsigned int phy_con30;
+	unsigned int phy_con31;
+	unsigned int phy_con32;
+	unsigned int phy_con33;
+	unsigned int phy_con34;
+	unsigned int phy_con35;
+	unsigned int phy_con36;
+	unsigned int phy_con37;
+	unsigned int phy_con38;
+	unsigned int phy_con39;
+	unsigned int phy_con40;
+	unsigned int phy_con41;
+	unsigned int phy_con42;
+};
+
+enum ddr_mode {
+	DDR_MODE_DDR2,
+	DDR_MODE_DDR3,
+	DDR_MODE_LPDDR2,
+	DDR_MODE_LPDDR3,
+
+	DDR_MODE_COUNT,
+};
+
+/* 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 impedeance */
+	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/cpu/samsung/exynos5420/dmc_common.c b/src/cpu/samsung/exynos5420/dmc_common.c
new file mode 100644
index 0000000..3abc3d3
--- /dev/null
+++ b/src/cpu/samsung/exynos5420/dmc_common.c
@@ -0,0 +1,183 @@
+/*
+ * 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 SMDK5420 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 manaully calibrating the ZQ values,
+	 * we are looping for the ZQ_init to complete.
+	 */
+	i = ZQ_INIT_TIMEOUT;
+	while ((readl(&phy0_ctrl->phy_con17) & ZQ_DONE) != ZQ_DONE && i > 0) {
+		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 Resyncronization */
+	val = readl(&dmc->phycontrol0);
+	val |= FP_RSYNC;
+	writel(val, &dmc->phycontrol0);
+
+	/* Reset Force DLL Resyncronization */
+	val = readl(&dmc->phycontrol0);
+	val &= ~FP_RSYNC;
+	writel(val, &dmc->phycontrol0);
+}
+
+void dmc_config_mrs(struct mem_timings *mem, struct exynos5_dmc *dmc)
+{
+	int channel, chip;
+
+	for (channel = 0; channel < mem->dmc_channels; channel++) {
+		unsigned long mask;
+
+		mask = channel << DIRECT_CMD_CHANNEL_SHIFT;
+		for (chip = 0; chip < mem->chips_to_configure; chip++) {
+			int i;
+
+			mask |= chip << DIRECT_CMD_CHIP_SHIFT;
+
+			/* Sending NOP command */
+			writel(DIRECT_CMD_NOP | mask, &dmc->directcmd);
+
+			/*
+			 * TODO(alim.akhtar at 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/cpu/samsung/exynos5420/dmc_init_ddr3.c b/src/cpu/samsung/exynos5420/dmc_init_ddr3.c
new file mode 100644
index 0000000..2d78087
--- /dev/null
+++ b/src/cpu/samsung/exynos5420/dmc_init_ddr3.c
@@ -0,0 +1,277 @@
+/*
+ * 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 SMDK5420 board based on EXYNOS5 */
+
+#include <console/console.h>
+#include <delay.h>
+#include <arch/io.h>
+#include "clk.h"
+#include "cpu.h"
+#include "dmc.h"
+#include "setup.h"
+
+#define RDLVL_COMPLETE_TIMEOUT	10000
+
+static void reset_phy_ctrl(void)
+{
+	struct exynos5_clock *clk = (struct exynos5_clock *)EXYNOS5_CLOCK_BASE;
+
+	writel(LPDDR3PHY_CTRL_PHY_RESET_OFF, &clk->lpddr3phy_ctrl);
+	writel(LPDDR3PHY_CTRL_PHY_RESET, &clk->lpddr3phy_ctrl);
+
+#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 at 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;
+	struct exynos5_phy_control *phy0_ctrl, *phy1_ctrl;
+	struct exynos5_dmc *dmc;
+	int i;
+
+	phy0_ctrl = (struct exynos5_phy_control *)EXYNOS5_DMC_PHY0_BASE;
+	phy1_ctrl = (struct exynos5_phy_control *)EXYNOS5_DMC_PHY1_BASE;
+	dmc = (struct exynos5_dmc *)EXYNOS5_DMC_CTRL_BASE;
+
+	if (mem_reset) {
+		printk(BIOS_SPEW, "%s: reset phy: ", __func__);
+		reset_phy_ctrl();
+		printk(BIOS_SPEW, "done\n");
+	} else {
+		printk(BIOS_SPEW, "%s: skip mem_reset.\n", __func__);
+	}
+
+	/* Set Impedance Output Driver */
+	printk(BIOS_SPEW, "ddr3_mem_ctrl_init: Set Impedance Output Driver\n");
+	printk(BIOS_SPEW, "ddr3_mem_ctrl_init: mem->impedance 0x%x\n",
+	       mem->impedance);
+	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);
+	printk(BIOS_SPEW, "ddr3_mem_ctrl_init: val 0x%x\n", val);
+	writel(val, &phy0_ctrl->phy_con39);
+	writel(val, &phy1_ctrl->phy_con39);
+
+	/* Set Read Latency and Burst Length for PHY0 and PHY1 */
+	printk(BIOS_SPEW, "ddr3_mem_ctrl_init: "
+	       "Set Read Latency and Burst Length for PHY0 and PHY1\n");
+	val = (mem->ctrl_bstlen << PHY_CON42_CTRL_BSTLEN_SHIFT) |
+		(mem->ctrl_rdlat << PHY_CON42_CTRL_RDLAT_SHIFT);
+	writel(val, &phy0_ctrl->phy_con42);
+	writel(val, &phy1_ctrl->phy_con42);
+
+	/* ZQ Calibration */
+	printk(BIOS_SPEW, "ddr3_mem_ctrl_init: ZQ Calibration\n");
+	if (dmc_config_zq(mem, phy0_ctrl, phy1_ctrl))
+		return SETUP_ERR_ZQ_CALIBRATION_FAILURE;
+
+	/* DQ Signal */
+	printk(BIOS_SPEW, "ddr3_mem_ctrl_init: DQ Signal\n");
+	writel(mem->phy0_pulld_dqs, &phy0_ctrl->phy_con14);
+	writel(mem->phy1_pulld_dqs, &phy1_ctrl->phy_con14);
+
+	writel(mem->concontrol | (mem->rd_fetch << CONCONTROL_RD_FETCH_SHIFT)
+		| (mem->dfi_init_start << CONCONTROL_DFI_INIT_START_SHIFT),
+		&dmc->concontrol);
+
+	update_reset_dll(dmc, DDR_MODE_DDR3);
+
+	/* DQS Signal */
+	printk(BIOS_SPEW, "ddr3_mem_ctrl_init: DQS Signal\n");
+	writel(mem->phy0_dqs, &phy0_ctrl->phy_con4);
+	writel(mem->phy1_dqs, &phy1_ctrl->phy_con4);
+
+	writel(mem->phy0_dq, &phy0_ctrl->phy_con6);
+	writel(mem->phy1_dq, &phy1_ctrl->phy_con6);
+
+	writel(mem->phy0_tFS, &phy0_ctrl->phy_con10);
+	writel(mem->phy1_tFS, &phy1_ctrl->phy_con10);
+
+	val = (mem->ctrl_start_point << PHY_CON12_CTRL_START_POINT_SHIFT) |
+		(mem->ctrl_inc << PHY_CON12_CTRL_INC_SHIFT) |
+		(mem->ctrl_dll_on << PHY_CON12_CTRL_DLL_ON_SHIFT) |
+		(mem->ctrl_ref << PHY_CON12_CTRL_REF_SHIFT);
+	writel(val, &phy0_ctrl->phy_con12);
+	writel(val, &phy1_ctrl->phy_con12);
+
+	/* Start DLL locking */
+	printk(BIOS_SPEW, "ddr3_mem_ctrl_init: Start DLL Locking\n");
+	writel(val | (mem->ctrl_start << PHY_CON12_CTRL_START_SHIFT),
+		&phy0_ctrl->phy_con12);
+	writel(val | (mem->ctrl_start << PHY_CON12_CTRL_START_SHIFT),
+		&phy1_ctrl->phy_con12);
+
+	update_reset_dll(dmc, DDR_MODE_DDR3);
+
+	writel(mem->concontrol | (mem->rd_fetch << CONCONTROL_RD_FETCH_SHIFT),
+		&dmc->concontrol);
+
+	/* Memory Channel Inteleaving Size */
+	printk(BIOS_SPEW, "ddr3_mem_ctrl_init: "
+	       "Memory Channel Inteleaving Size\n");
+	writel(mem->iv_size, &dmc->ivcontrol);
+
+	/* Set DMC MEMCONTROL register */
+	printk(BIOS_SPEW, "ddr3_mem_ctrl_init: Set DMC MEMCONTROL register\n");
+	val = mem->memcontrol & ~DMC_MEMCONTROL_DSREF_ENABLE;
+	writel(val, &dmc->memcontrol);
+
+	writel(mem->memconfig, &dmc->memconfig0);
+	writel(mem->memconfig, &dmc->memconfig1);
+	writel(mem->membaseconfig0, &dmc->membaseconfig0);
+	writel(mem->membaseconfig1, &dmc->membaseconfig1);
+
+	/* Precharge Configuration */
+	printk(BIOS_SPEW, "ddr3_mem_ctrl_init: Precharge Configuration\n");
+	writel(mem->prechconfig_tp_cnt << PRECHCONFIG_TP_CNT_SHIFT,
+		&dmc->prechconfig);
+
+	/* Power Down mode Configuration */
+	printk(BIOS_SPEW, "ddr3_mem_ctrl_init: "
+	       "Power Down mode Configuraation\n");
+	writel(mem->dpwrdn_cyc << PWRDNCONFIG_DPWRDN_CYC_SHIFT |
+		mem->dsref_cyc << PWRDNCONFIG_DSREF_CYC_SHIFT,
+		&dmc->pwrdnconfig);
+
+	/* TimingRow, TimingData, TimingPower and Timingaref
+	 * values as per Memory AC parameters
+	 */
+	printk(BIOS_SPEW, "ddr3_mem_ctrl_init: "
+	       "TimingRow, TimingData, TimingPower and Timingaref\n");
+	writel(mem->timing_ref, &dmc->timingref);
+	writel(mem->timing_row, &dmc->timingrow);
+	writel(mem->timing_data, &dmc->timingdata);
+	writel(mem->timing_power, &dmc->timingpower);
+
+	/* Send PALL command */
+	printk(BIOS_SPEW, "ddr3_mem_ctrl_init: Send PALL Command\n");
+	dmc_config_prech(mem, dmc);
+
+	/* Send NOP, MRS and ZQINIT commands */
+	printk(BIOS_SPEW, "ddr3_mem_ctrl_init: Send NOP, MRS, and ZQINIT\n");
+	dmc_config_mrs(mem, dmc);
+
+	if (mem->gate_leveling_enable) {
+		val = PHY_CON0_RESET_VAL;
+		val |= P0_CMD_EN;
+		writel(val, &phy0_ctrl->phy_con0);
+		writel(val, &phy1_ctrl->phy_con0);
+
+		val = PHY_CON2_RESET_VAL;
+		val |= INIT_DESKEW_EN;
+		writel(val, &phy0_ctrl->phy_con2);
+		writel(val, &phy1_ctrl->phy_con2);
+
+		val = PHY_CON0_RESET_VAL;
+		val |= P0_CMD_EN;
+		val |= BYTE_RDLVL_EN;
+		writel(val, &phy0_ctrl->phy_con0);
+		writel(val, &phy1_ctrl->phy_con0);
+
+		val = (mem->ctrl_start_point <<
+				PHY_CON12_CTRL_START_POINT_SHIFT) |
+			(mem->ctrl_inc << PHY_CON12_CTRL_INC_SHIFT) |
+			(mem->ctrl_force << PHY_CON12_CTRL_FORCE_SHIFT) |
+			(mem->ctrl_start << PHY_CON12_CTRL_START_SHIFT) |
+			(mem->ctrl_ref << PHY_CON12_CTRL_REF_SHIFT);
+		writel(val, &phy0_ctrl->phy_con12);
+		writel(val, &phy1_ctrl->phy_con12);
+
+		val = PHY_CON2_RESET_VAL;
+		val |= INIT_DESKEW_EN;
+		val |= RDLVL_GATE_EN;
+		writel(val, &phy0_ctrl->phy_con2);
+		writel(val, &phy1_ctrl->phy_con2);
+
+		val = PHY_CON0_RESET_VAL;
+		val |= P0_CMD_EN;
+		val |= BYTE_RDLVL_EN;
+		val |= CTRL_SHGATE;
+		writel(val, &phy0_ctrl->phy_con0);
+		writel(val, &phy1_ctrl->phy_con0);
+
+		val = PHY_CON1_RESET_VAL;
+		val &= ~(CTRL_GATEDURADJ_MASK);
+		writel(val, &phy0_ctrl->phy_con1);
+		writel(val, &phy1_ctrl->phy_con1);
+
+		writel(CTRL_RDLVL_GATE_ENABLE, &dmc->rdlvl_config);
+		i = RDLVL_COMPLETE_TIMEOUT;
+		while ((readl(&dmc->phystatus) &
+			(RDLVL_COMPLETE_CHO | RDLVL_COMPLETE_CH1)) !=
+			(RDLVL_COMPLETE_CHO | RDLVL_COMPLETE_CH1) && i > 0) {
+			/*
+			 * TODO(waihong): Comment on how long this take to
+			 * timeout
+			 */
+			udelay(1);
+			i--;
+		}
+		if (!i){
+			printk(BIOS_SPEW, "Timeout on RDLVL. No DRAM.\n");
+			return SETUP_ERR_RDLV_COMPLETE_TIMEOUT;
+		}
+		writel(CTRL_RDLVL_GATE_DISABLE, &dmc->rdlvl_config);
+
+		writel(0, &phy0_ctrl->phy_con14);
+		writel(0, &phy1_ctrl->phy_con14);
+
+		val = (mem->ctrl_start_point <<
+				PHY_CON12_CTRL_START_POINT_SHIFT) |
+			(mem->ctrl_inc << PHY_CON12_CTRL_INC_SHIFT) |
+			(mem->ctrl_force << PHY_CON12_CTRL_FORCE_SHIFT) |
+			(mem->ctrl_start << PHY_CON12_CTRL_START_SHIFT) |
+			(mem->ctrl_dll_on << PHY_CON12_CTRL_DLL_ON_SHIFT) |
+			(mem->ctrl_ref << PHY_CON12_CTRL_REF_SHIFT);
+		writel(val, &phy0_ctrl->phy_con12);
+		writel(val, &phy1_ctrl->phy_con12);
+
+		update_reset_dll(dmc, DDR_MODE_DDR3);
+	}
+
+	/* Send PALL command */
+	printk(BIOS_SPEW, "ddr3_mem_ctrl_init: Send PALL Command\n");
+	dmc_config_prech(mem, dmc);
+
+	writel(mem->memcontrol, &dmc->memcontrol);
+
+	/* Set DMC Concontrol and enable auto-refresh counter */
+	printk(BIOS_SPEW, "ddr3_mem_ctrl_init: "
+	       "Set DMC Concontrol and enable auto-refresh counter\n");
+	writel(mem->concontrol | (mem->rd_fetch << CONCONTROL_RD_FETCH_SHIFT)
+		| (mem->aref_en << CONCONTROL_AREF_EN_SHIFT), &dmc->concontrol);
+	return 0;
+}
diff --git a/src/cpu/samsung/exynos5420/dp-core.h b/src/cpu/samsung/exynos5420/dp-core.h
new file mode 100644
index 0000000..7b81037
--- /dev/null
+++ b/src/cpu/samsung/exynos5420/dp-core.h
@@ -0,0 +1,268 @@
+/*
+ * 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_EXYNOS5420_DP_CORE_H
+#define CPU_SAMSUNG_EXYNOS5420_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 tare 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;
+};
+
+/* this struct is used by mainboards to pass mode info to the driver */
+typedef struct vidinfo {
+	u16 vl_col;
+	u16 vl_row;
+	u8 vl_bpix;
+	u16 *cmap;
+} vidinfo_t;
+
+/* 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 recieve 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 caluculate m_vid value
+ * param n_value	to caluculate 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(vidinfo_t *panel_info, void *lcdbase,
+				struct exynos5_fimd_panel *pd);
+int dp_controller_init(struct s5p_dp_device *dp_device);
+int lcd_ctrl_init(vidinfo_t *panel_info,
+			struct exynos5_fimd_panel *panel_data, void *lcdbase);
+#endif /* CPU_SAMSUNG_EXYNOS5420_DP_CORE_H */
diff --git a/src/cpu/samsung/exynos5420/dp-reg.c b/src/cpu/samsung/exynos5420/dp-reg.c
new file mode 100644
index 0000000..eb53356
--- /dev/null
+++ b/src/cpu/samsung/exynos5420/dp-reg.c
@@ -0,0 +1,495 @@
+/*
+ * 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 regisers */
+	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;
+	u32 start;
+	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);
+
+		start = get_timer(0);
+		while (s5p_dp_get_pll_lock_status(dp) == PLL_UNLOCKED) {
+			if (get_timer(start) > PLL_LOCK_TIMEOUT) {
+				printk(BIOS_ERR, "%s: PLL is not locked\n",
+						__func__);
+				return -1;
+			}
+		}
+	}
+
+	/* 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 inerrupts 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;
+	u32 start;
+	struct exynos5_dp *base = dp->base;
+
+	/* Wait for 4 VSYNC_DET interrupts */
+	start = get_timer(0);
+	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;
+	} while (get_timer(start) <= STREAM_ON_TIMEOUT);
+
+	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/cpu/samsung/exynos5420/dp.h b/src/cpu/samsung/exynos5420/dp.h
new file mode 100644
index 0000000..46579b3
--- /dev/null
+++ b/src/cpu/samsung/exynos5420/dp.h
@@ -0,0 +1,497 @@
+/*
+ * 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_EXYNOS5420_DP_H
+#define CPU_SAMSUNG_EXYNOS5420_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;
+};
+/* 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/cpu/samsung/exynos5420/dsim.h b/src/cpu/samsung/exynos5420/dsim.h
new file mode 100644
index 0000000..25015a2
--- /dev/null
+++ b/src/cpu/samsung/exynos5420/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_EXYNOS5420_DSIM_H
+#define CPU_SAMSUNG_EXYNOS5420_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/cpu/samsung/exynos5420/fb.c b/src/cpu/samsung/exynos5420/fb.c
new file mode 100644
index 0000000..d4c3d44
--- /dev/null
+++ b/src/cpu/samsung/exynos5420/fb.c
@@ -0,0 +1,597 @@
+/*
+ * 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 <arch/io.h>
+#include <stdlib.h>
+#include <string.h>
+#include <timer.h>
+#include <delay.h>
+#include <console/console.h>
+#include "timer.h"
+#include "cpu.h"
+#include "power.h"
+#include "sysreg.h"
+#include <drivers/maxim/max77686/max77686.h>
+
+#include "device/i2c.h"
+#include "i2c.h"
+#include "fimd.h"
+#include "dp.h"
+#include "dp-core.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)
+{
+	struct exynos5_sysreg *sysreg = samsung_get_base_sysreg();
+
+	setbits_le32(&sysreg->disp1blk_cfg, FIMDBYPASS_DISP1);
+	sysreg->disp1blk_cfg &= ~FIMDBYPASS_DISP1;
+}
+
+/* Calculate the size of Framebuffer from the resolution */
+static u32 calc_fbsize(vidinfo_t *panel_info)
+{
+	/* They had PAGE_SIZE here instead of 4096.
+	 * but that's a totally arbitrary number -- everything nowadays
+	 * has lots of page sizes.
+	 * So keep it obvious.
+	 */
+	return ALIGN((panel_info->vl_col * panel_info->vl_row *
+		      ((1<<panel_info->vl_bpix) / 8)), 4096);
+}
+
+/*
+ * Initialize display controller.
+ *
+ * @param lcdbase	pointer to the base address of framebuffer.
+ * @pd			pointer to the main panel_data structure
+ */
+void fb_init(vidinfo_t *panel_info, void *lcdbase,
+	struct exynos5_fimd_panel *pd)
+{
+	unsigned int val;
+	u32 fbsize;
+	struct exynos5_fimd *fimd = samsung_get_base_fimd();
+	struct exynos5_disp_ctrl *disp_ctrl = samsung_get_base_disp_ctrl();
+
+	writel(pd->ivclk | pd->fixvclk, &disp_ctrl->vidcon1);
+	val = ENVID_ON | ENVID_F_ON | (pd->clkval_f << CLKVAL_F_OFFSET);
+	writel(val, &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, &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, &disp_ctrl->vidtcon1);
+
+	val = ((pd->xres - 1) << HOZVAL_OFFSET) |
+		((pd->yres - 1) << LINEVAL_OFFSET);
+	writel(val, &disp_ctrl->vidtcon2);
+
+	writel((unsigned int)lcdbase, &fimd->vidw00add0b0);
+
+	fbsize = calc_fbsize(panel_info);
+	writel((unsigned int)lcdbase + fbsize, &fimd->vidw00add1b0);
+
+	writel(pd->xres * 2, &fimd->vidw00add2);
+
+	val = ((pd->xres - 1) << OSD_RIGHTBOTX_F_OFFSET);
+	val |= ((pd->yres - 1) << OSD_RIGHTBOTY_F_OFFSET);
+	writel(val, &fimd->vidosd0b);
+	writel(pd->xres * pd->yres, &fimd->vidosd0c);
+
+	setbits_le32(&fimd->shadowcon, CHANNEL0_EN);
+
+	val = BPPMODE_F_RGB_16BIT_565 << BPPMODE_F_OFFSET;
+	val |= ENWIN_F_ENABLE | HALF_WORD_SWAP_EN;
+	writel(val, &fimd->wincon0);
+
+	/* DPCLKCON_ENABLE */
+	writel(1 << 1, &fimd->dpclkcon);
+}
+
+#ifdef UNUSED_CODE
+void exynos_fimd_disable(void)
+{
+	struct exynos5_fimd *fimd = samsung_get_base_fimd();
+
+	writel(0, &fimd->wincon0);
+	clrbits_le32(&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(&current);
+	} while (mono_time_before(&current, &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;
+	u32 start;
+	int lane;
+	struct exynos5_dp *base = dp->base;
+
+	/* Stop Video */
+	clrbits_le32(&base->video_ctl_1, VIDEO_EN);
+
+	start = get_timer(0);
+	while ((pll_is_locked = s5p_dp_get_pll_lock_status(dp)) == PLL_UNLOCKED) {
+		if (get_timer(start) > PLL_LOCK_TIMEOUT) {
+			/* Ignore this error, and try to continue */
+			printk(BIOS_ERR, "PLL is not locked yet.\n");
+			break;
+		}
+	}
+	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(vidinfo_t *panel_info,
+		struct exynos5_fimd_panel *panel_data, void *lcdbase)
+{
+	int ret = 0;
+
+	fimd_bypass();
+	fb_init(panel_info, lcdbase, panel_data);
+	return ret;
+}
diff --git a/src/cpu/samsung/exynos5420/fimd.h b/src/cpu/samsung/exynos5420/fimd.h
new file mode 100644
index 0000000..661ed9e
--- /dev/null
+++ b/src/cpu/samsung/exynos5420/fimd.h
@@ -0,0 +1,138 @@
+/*
+ * 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_EXYNOS5420_FIMD_H
+#define CPU_SAMSUNG_EXYNOS5420_FIMD_H
+
+/* FIMD register map */
+struct exynos5_fimd {
+	/* This is an incomplete list. Add registers as and when required */
+	unsigned int vidcon0;
+	unsigned char res1[0x1c];
+	unsigned int wincon0;
+	unsigned int wincon1;
+	unsigned int wincon2;
+	unsigned int wincon3;
+	unsigned int wincon4;
+	unsigned int shadowcon;
+	unsigned char res2[0x8];
+	unsigned int vidosd0a;
+	unsigned int vidosd0b;
+	unsigned int vidosd0c;
+	unsigned char res3[0x54];
+	unsigned int vidw00add0b0;
+	unsigned char res4[0x2c];
+	unsigned int vidw00add1b0;
+	unsigned char res5[0x2c];
+	unsigned int vidw00add2;
+	unsigned char res6[0x3c];
+	unsigned int w1keycon0;
+	unsigned int w1keycon1;
+	unsigned int w2keycon0;
+	unsigned int w2keycon1;
+	unsigned int w3keycon0;
+	unsigned int w3keycon1;
+	unsigned int w4keycon0;
+	unsigned int w4keycon1;
+	unsigned char res7[0x20];
+	unsigned int win0map;
+	unsigned char res8[0xdc];
+	unsigned int blendcon;
+	unsigned char res9[0x18];
+	unsigned int dpclkcon;
+};
+
+#define W0_SHADOW_PROTECT	(0x1 << 10)
+#define COMPKEY_F		0xffffff
+#define ENVID_F_ON		(0x1 << 0)
+#define ENVID_ON		(0x1 << 1)
+#define CLKVAL_F		0xb
+#define CLKVAL_F_OFFSET		6
+
+/*
+ * Structure containing display panel specific data for FIMD
+ */
+struct exynos5_fimd_panel {
+	unsigned int is_dp:1;		/* Display Panel interface is eDP */
+	unsigned int is_mipi:1;		/* Display Panel interface is MIPI */
+	unsigned int fixvclk:2;	/* VCLK hold scheme at data underflow */
+
+	/*
+	 * Polarity of the VCLK active edge
+	 *	0-falling
+	 *	1-rising
+	 */
+	unsigned int ivclk:1;
+	unsigned int clkval_f;		/* Divider to create pixel clock */
+
+	unsigned int upper_margin;	/* Vertical Backporch */
+	unsigned int lower_margin;	/* Vertical frontporch */
+	unsigned int vsync;		/* Vertical Sync Pulse Width */
+	unsigned int left_margin;	/* Horizantal Backporch */
+	unsigned int right_margin;	/* Horizontal Frontporch */
+	unsigned int hsync;		/* Horizontal Sync Pulse Width */
+	unsigned int xres;		/* X Resolution */
+	unsigned int yres;		/* Y Resopultion */
+};
+
+/* LCDIF Register Map */
+struct exynos5_disp_ctrl {
+	unsigned int vidout_con;
+	unsigned int vidcon1;
+	unsigned char res1[0x8];
+	unsigned int vidtcon0;
+	unsigned int vidtcon1;
+	unsigned int vidtcon2;
+	unsigned int vidtcon3;
+	unsigned char res2[0x184];
+	unsigned int trigcon;
+};
+
+#define VCLK_RISING_EDGE		(1 << 7)
+#define VCLK_RUNNING			(1 << 9)
+
+#define CHANNEL0_EN			(1 << 0)
+
+#define VSYNC_PULSE_WIDTH_VAL		0x3
+#define VSYNC_PULSE_WIDTH_OFFSET	0
+#define V_FRONT_PORCH_VAL		0x3
+#define V_FRONT_PORCH_OFFSET		8
+#define V_BACK_PORCH_VAL		0x3
+#define V_BACK_PORCH_OFFSET		16
+
+#define HSYNC_PULSE_WIDTH_VAL		0x3
+#define HSYNC_PULSE_WIDTH_OFFSET	0
+#define H_FRONT_PORCH_VAL		0x3
+#define H_FRONT_PORCH_OFFSET		8
+#define H_BACK_PORCH_VAL		0x3
+#define H_BACK_PORCH_OFFSET		16
+
+#define HOZVAL_OFFSET	0
+#define LINEVAL_OFFSET	11
+
+#define BPPMODE_F_RGB_16BIT_565		0x5
+#define BPPMODE_F_OFFSET		2
+#define ENWIN_F_ENABLE			(1 << 0)
+#define HALF_WORD_SWAP_EN		(1 << 16)
+
+#define OSD_RIGHTBOTX_F_OFFSET		11
+#define OSD_RIGHTBOTY_F_OFFSET		0
+#endif
diff --git a/src/cpu/samsung/exynos5420/gpio.c b/src/cpu/samsung/exynos5420/gpio.c
new file mode 100644
index 0000000..b8ebb0a
--- /dev/null
+++ b/src/cpu/samsung/exynos5420/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);
+
+	gpio_cfg_pin(gpio, GPIO_OUTPUT);
+
+	val = readl(&bank->dat);
+	val &= ~DAT_MASK(GPIO_BIT(gpio));
+	if (value)
+		val |= DAT_SET(GPIO_BIT(gpio));
+	writel(val, &bank->dat);
+
+	return 0;
+}
+
+int gpio_get_value(unsigned gpio)
+{
+	unsigned int value;
+	struct 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/cpu/samsung/exynos5420/gpio.h b/src/cpu/samsung/exynos5420/gpio.h
new file mode 100644
index 0000000..0787826
--- /dev/null
+++ b/src/cpu/samsung/exynos5420/gpio.h
@@ -0,0 +1,578 @@
+/*
+ * 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_EXYNOS5420_GPIO_H
+#define CPU_SAMSUNG_EXYNOS5420_GPIO_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
+
+#define EXYNOS5_GPIO_BASE0	0x11400000
+#define EXYNOS5_GPIO_BASE1	0x13400000
+#define EXYNOS5_GPIO_BASE2	0x10d10000
+#define EXYNOS5_GPIO_BASE3	0x03860000
+
+enum exynos5_gpio_port {
+	/*
+	 * Ordered by base address + offset.
+	 * ETC registers are special, thus not included.
+	 */
+
+	/* base == EXYNOS_GPIO_BASE0 */
+	EXYNOS5_GPA0 = EXYNOS5_GPIO_BASE0 + 0x0000,
+	EXYNOS5_GPA1 = EXYNOS5_GPIO_BASE0 + 0x0020,
+	EXYNOS5_GPA2 = EXYNOS5_GPIO_BASE0 + 0x0040,
+
+	EXYNOS5_GPB0 = EXYNOS5_GPIO_BASE0 + 0x0060,
+	EXYNOS5_GPB1 = EXYNOS5_GPIO_BASE0 + 0x0080,
+	EXYNOS5_GPB2 = EXYNOS5_GPIO_BASE0 + 0x00a0,
+	EXYNOS5_GPB3 = EXYNOS5_GPIO_BASE0 + 0x00c0,
+
+	EXYNOS5_GPC0 = EXYNOS5_GPIO_BASE0 + 0x00e0,
+	EXYNOS5_GPC1 = EXYNOS5_GPIO_BASE0 + 0x0100,
+	EXYNOS5_GPC2 = EXYNOS5_GPIO_BASE0 + 0x0120,
+	EXYNOS5_GPC3 = EXYNOS5_GPIO_BASE0 + 0x0140,
+
+	EXYNOS5_GPD0 = EXYNOS5_GPIO_BASE0 + 0x0160,
+	EXYNOS5_GPD1 = EXYNOS5_GPIO_BASE0 + 0x0180,
+
+	EXYNOS5_GPY0 = EXYNOS5_GPIO_BASE0 + 0x01a0,
+	EXYNOS5_GPY1 = EXYNOS5_GPIO_BASE0 + 0x01c0,
+	EXYNOS5_GPY2 = EXYNOS5_GPIO_BASE0 + 0x01e0,
+	EXYNOS5_GPY3 = EXYNOS5_GPIO_BASE0 + 0x0200,
+	EXYNOS5_GPY4 = EXYNOS5_GPIO_BASE0 + 0x0220,
+	EXYNOS5_GPY5 = EXYNOS5_GPIO_BASE0 + 0x0240,
+	EXYNOS5_GPY6 = EXYNOS5_GPIO_BASE0 + 0x0260,
+
+	EXYNOS5_GPX0 = EXYNOS5_GPIO_BASE0 + 0x0c00,
+	EXYNOS5_GPX1 = EXYNOS5_GPIO_BASE0 + 0x0c20,
+	EXYNOS5_GPX2 = EXYNOS5_GPIO_BASE0 + 0x0c40,
+	EXYNOS5_GPX3 = EXYNOS5_GPIO_BASE0 + 0x0c60,
+
+	/* base == EXYNOS_GPIO_BASE1 */
+	EXYNOS5_GPE0 = EXYNOS5_GPIO_BASE1 + 0x0000,
+	EXYNOS5_GPE1 = EXYNOS5_GPIO_BASE1 + 0x0020,
+
+	EXYNOS5_GPF0 = EXYNOS5_GPIO_BASE1 + 0x0040,
+	EXYNOS5_GPF1 = EXYNOS5_GPIO_BASE1 + 0x0060,
+
+	EXYNOS5_GPG0 = EXYNOS5_GPIO_BASE1 + 0x0080,
+	EXYNOS5_GPG1 = EXYNOS5_GPIO_BASE1 + 0x00a0,
+	EXYNOS5_GPG2 = EXYNOS5_GPIO_BASE1 + 0x00c0,
+
+	EXYNOS5_GPH0 = EXYNOS5_GPIO_BASE1 + 0x00e0,
+	EXYNOS5_GPH1 = EXYNOS5_GPIO_BASE1 + 0x0100,
+
+	/* base == EXYNOS_GPIO_BASE2 */
+	EXYNOS5_GPV0 = EXYNOS5_GPIO_BASE2 + 0x0000,
+	EXYNOS5_GPV1 = EXYNOS5_GPIO_BASE2 + 0x0020,
+	EXYNOS5_GPV2 = EXYNOS5_GPIO_BASE2 + 0x0060,
+	EXYNOS5_GPV3 = EXYNOS5_GPIO_BASE2 + 0x0080,
+	EXYNOS5_GPV4 = EXYNOS5_GPIO_BASE2 + 0x00c0,
+
+	/* base == EXYNOS_GPIO_BASE3 */
+	EXYNOS5_GPZ = EXYNOS5_GPIO_BASE3 + 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_EXYNOS5420_GPIO_H */
diff --git a/src/cpu/samsung/exynos5420/i2c.c b/src/cpu/samsung/exynos5420/i2c.c
new file mode 100644
index 0000000..98eb641
--- /dev/null
+++ b/src/cpu/samsung/exynos5420/i2c.c
@@ -0,0 +1,405 @@
+/*
+ * This file is part of the coreboot project.
+ *
+ * (C) Copyright 2002
+ * David Mueller, ELSOFT AG, d.mueller at 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"
+#include "pinmux.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)
+{
+	exynos_pinmux_config(bus->periph_id, 0);
+	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, unsigned char *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, unsigned char *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, buf, len);
+
+	return ret != 0;
+}
diff --git a/src/cpu/samsung/exynos5420/i2c.h b/src/cpu/samsung/exynos5420/i2c.h
new file mode 100644
index 0000000..b14aa79
--- /dev/null
+++ b/src/cpu/samsung/exynos5420/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_EXYNOS5420_I2C_H
+#define CPU_SAMSUNG_EXYNOS5420_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_EXYNOS5420_I2C_H */
diff --git a/src/cpu/samsung/exynos5420/i2s-regs.h b/src/cpu/samsung/exynos5420/i2s-regs.h
new file mode 100644
index 0000000..28d2685
--- /dev/null
+++ b/src/cpu/samsung/exynos5420/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_EXYNOS5420_I2S_REGS_H
+#define CPU_SAMSUNG_EXYNOS5420_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_EXYNOS5420_I2S_REGS_H */
diff --git a/src/cpu/samsung/exynos5420/mct.c b/src/cpu/samsung/exynos5420/mct.c
new file mode 100644
index 0000000..4c5cdd1
--- /dev/null
+++ b/src/cpu/samsung/exynos5420/mct.c
@@ -0,0 +1,104 @@
+/*
+ * 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"
+
+struct __attribute__((packed)) mct_regs
+{
+	uint32_t mct_cfg;
+	uint8_t reserved0[0xfc];
+	uint32_t g_cnt_l;
+	uint32_t g_cnt_u;
+	uint8_t reserved1[0x8];
+	uint32_t g_cnt_wstat;
+	uint8_t reserved2[0xec];
+	uint32_t g_comp0_l;
+	uint32_t g_comp0_u;
+	uint32_t g_comp0_addr_incr;
+	uint8_t reserved3[0x4];
+	uint32_t g_comp1_l;
+	uint32_t g_comp1_u;
+	uint32_t g_comp1_addr_incr;
+	uint8_t reserved4[0x4];
+	uint32_t g_comp2_l;
+	uint32_t g_comp2_u;
+	uint32_t g_comp2_addr_incr;
+	uint8_t reserved5[0x4];
+	uint32_t g_comp3_l;
+	uint32_t g_comp3_u;
+	uint32_t g_comp3_addr_incr;
+	uint8_t reserved6[0x4];
+	uint32_t g_tcon;
+	uint32_t g_int_cstat;
+	uint32_t g_int_enb;
+	uint32_t g_wstat;
+	uint8_t reserved7[0xb0];
+	uint32_t l0_tcntb;
+	uint32_t l0_tcnto;
+	uint32_t l0_icntb;
+	uint32_t l0_icnto;
+	uint32_t l0_frcntb;
+	uint32_t l0_frcnto;
+	uint8_t reserved8[0x8];
+	uint32_t l0_tcon;
+	uint8_t reserved9[0xc];
+	uint32_t l0_int_cstat;
+	uint32_t l0_int_enb;
+	uint8_t reserved10[0x8];
+	uint32_t l0_wstat;
+	uint8_t reserved11[0xbc];
+	uint32_t l1_tcntb;
+	uint32_t l1_tcnto;
+	uint32_t l1_icntb;
+	uint32_t l1_icnto;
+	uint32_t l1_frcntb;
+	uint32_t l1_frcnto;
+	uint8_t reserved12[0x8];
+	uint32_t l1_tcon;
+	uint8_t reserved13[0xc];
+	uint32_t l1_int_cstat;
+	uint32_t l1_int_enb;
+	uint8_t reserved14[0x8];
+	uint32_t l1_wstat;
+};
+
+static int enabled = 0;
+static struct mct_regs *const mct =
+	(struct mct_regs *)MCT_ADDRESS;
+
+uint64_t mct_raw_value(void)
+{
+	if (!enabled) {
+		writel(readl(&mct->g_tcon) | (0x1 << 8), &mct->g_tcon);
+		enabled = 1;
+	}
+
+	uint64_t upper = readl(&mct->g_cnt_u);
+	uint64_t lower = readl(&mct->g_cnt_l);
+
+	return (upper << 32) | lower;
+}
+
+void mct_start(void)
+{
+	writel(readl(&mct->g_tcon) | (0x1 << 8), &mct->g_tcon);
+	enabled = 1;
+}
diff --git a/src/cpu/samsung/exynos5420/monotonic_timer.c b/src/cpu/samsung/exynos5420/monotonic_timer.c
new file mode 100644
index 0000000..6350af5
--- /dev/null
+++ b/src/cpu/samsung/exynos5420/monotonic_timer.c
@@ -0,0 +1,57 @@
+/*
+ * 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 <delay.h>
+#include <timer.h>
+
+#include "clk.h"
+
+static struct monotonic_counter {
+	int initialized;
+	struct mono_time time;
+	uint64_t last_value;
+} mono_counter;
+
+static const uint32_t clocks_per_usec = MCT_HZ/1000000;
+
+void timer_monotonic_get(struct mono_time *mt)
+{
+	uint64_t current_tick;
+	uint64_t usecs_elapsed;
+
+	if (!mono_counter.initialized) {
+		init_timer();
+		mono_counter.last_value = mct_raw_value();
+		mono_counter.initialized = 1;
+	}
+
+	current_tick = mct_raw_value();
+	usecs_elapsed = (current_tick - mono_counter.last_value) /
+							clocks_per_usec;
+
+	/* Update current time and tick values only if a full tick occurred. */
+	if (usecs_elapsed) {
+		mono_time_add_usecs(&mono_counter.time, usecs_elapsed);
+		mono_counter.last_value = current_tick;
+	}
+
+	/* Save result. */
+	*mt = mono_counter.time;
+}
diff --git a/src/cpu/samsung/exynos5420/periph.h b/src/cpu/samsung/exynos5420/periph.h
new file mode 100644
index 0000000..3981662
--- /dev/null
+++ b/src/cpu/samsung/exynos5420/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_EXYNOS5420_PERIPH_H
+#define CPU_SAMSUNG_EXYNOS5420_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/cpu/samsung/exynos5420/pinmux.c b/src/cpu/samsung/exynos5420/pinmux.c
new file mode 100644
index 0000000..6991dfc
--- /dev/null
+++ b/src/cpu/samsung/exynos5420/pinmux.c
@@ -0,0 +1,298 @@
+/*
+ * 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 "cpu.h"
+#include "pinmux.h"
+
+int exynos_pinmux_config(enum periph_id peripheral, int flags)
+{
+	int i, start, count, start_ext, pin_ext, pin, drv;
+
+	switch (peripheral) {
+	case PERIPH_ID_UART0:
+	case PERIPH_ID_UART1:
+	case PERIPH_ID_UART2:
+	case PERIPH_ID_UART3:
+		switch (peripheral) {
+		default:
+		case PERIPH_ID_UART0:
+			start = GPIO_A00; count = 4;
+			break;
+		case PERIPH_ID_UART1:
+			start = GPIO_A04; count = 4;
+			break;
+		case PERIPH_ID_UART2:
+			start = GPIO_A10; count = 4;
+			break;
+		case PERIPH_ID_UART3:
+			start = GPIO_A14; count = 2;
+			break;
+		}
+		for (i = start; i < start + count; i++) {
+			gpio_set_pull(i, GPIO_PULL_NONE);
+			gpio_cfg_pin(i, GPIO_FUNC(0x2));
+		}
+		break;
+	case PERIPH_ID_SDMMC0:
+	case PERIPH_ID_SDMMC1:
+	case PERIPH_ID_SDMMC2:
+	case PERIPH_ID_SDMMC3:
+		pin = GPIO_FUNC(0x2);
+		pin_ext = GPIO_FUNC(0x2);
+		drv = GPIO_DRV_4X;
+		switch (peripheral) {
+		default:
+		case PERIPH_ID_SDMMC0:
+			start = GPIO_C00;
+			start_ext = GPIO_C10;
+			break;
+		case PERIPH_ID_SDMMC1:
+			start = GPIO_C20;
+			start_ext = 0;
+			break;
+		case PERIPH_ID_SDMMC2:
+			start = GPIO_C30;
+			/*
+			 * TODO: (alim.akhtar at samsung.com)
+			 * add support for 8 bit mode (needs to be a per-board
+			 * option, so in the FDT).
+			 */
+			start_ext = 0;
+			break;
+		case PERIPH_ID_SDMMC3:
+			/*
+			 * TODO: Need to add defintions for GPC4 before
+			 * enabling this.
+			 */
+			printk(BIOS_DEBUG, "SDMMC3 not supported yet");
+			return -1;
+		}
+		if ((flags & PINMUX_FLAG_8BIT_MODE) && !start_ext) {
+			printk(BIOS_DEBUG, "SDMMC device %d does not support 8bit mode",
+					peripheral);
+			return -1;
+		}
+		if (flags & PINMUX_FLAG_8BIT_MODE) {
+			ASSERT(peripheral == PERIPH_ID_SDMMC0);
+			for (i = 0; i <= 3; i++) {
+				gpio_cfg_pin(start_ext + i, pin_ext);
+				gpio_set_pull(start_ext + i,
+					      GPIO_PULL_UP);
+				gpio_set_drv(start_ext + i, drv);
+			}
+		}
+		for (i = 0; i < 2; i++) {
+			gpio_cfg_pin(start + i, pin);
+			gpio_set_pull(start + i, GPIO_PULL_NONE);
+			gpio_set_drv(start + i, drv);
+		}
+		for (i = 2; i <= 6; i++) {
+			gpio_cfg_pin(start + i, pin);
+			gpio_set_pull(start + i, GPIO_PULL_UP);
+			gpio_set_drv(start + i, drv);
+		}
+		break;
+	case PERIPH_ID_SROMC:
+		/*
+		 * SROM:CS1 and EBI
+		 *
+		 * GPY0[0]	SROM_CSn[0]
+		 * GPY0[1]	SROM_CSn[1](2)
+		 * GPY0[2]	SROM_CSn[2]
+		 * GPY0[3]	SROM_CSn[3]
+		 * GPY0[4]	EBI_OEn(2)
+		 * GPY0[5]	EBI_EEn(2)
+		 *
+		 * GPY1[0]	EBI_BEn[0](2)
+		 * GPY1[1]	EBI_BEn[1](2)
+		 * GPY1[2]	SROM_WAIT(2)
+		 * GPY1[3]	EBI_DATA_RDn(2)
+		 */
+		gpio_cfg_pin(GPIO_Y00 + (flags & PINMUX_FLAG_BANK),
+				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));
+
+		/*
+		 * EBI: 8 Addrss Lines
+		 *
+		 * GPY3[0]	EBI_ADDR[0](2)
+		 * GPY3[1]	EBI_ADDR[1](2)
+		 * GPY3[2]	EBI_ADDR[2](2)
+		 * GPY3[3]	EBI_ADDR[3](2)
+		 * GPY3[4]	EBI_ADDR[4](2)
+		 * GPY3[5]	EBI_ADDR[5](2)
+		 * GPY3[6]	EBI_ADDR[6](2)
+		 * GPY3[7]	EBI_ADDR[7](2)
+		 *
+		 * EBI: 16 Data Lines
+		 *
+		 * GPY5[0]	EBI_DATA[0](2)
+		 * GPY5[1]	EBI_DATA[1](2)
+		 * GPY5[2]	EBI_DATA[2](2)
+		 * GPY5[3]	EBI_DATA[3](2)
+		 * GPY5[4]	EBI_DATA[4](2)
+		 * GPY5[5]	EBI_DATA[5](2)
+		 * GPY5[6]	EBI_DATA[6](2)
+		 * GPY5[7]	EBI_DATA[7](2)
+		 *
+		 * GPY6[0]	EBI_DATA[8](2)
+		 * GPY6[1]	EBI_DATA[9](2)
+		 * GPY6[2]	EBI_DATA[10](2)
+		 * GPY6[3]	EBI_DATA[11](2)
+		 * GPY6[4]	EBI_DATA[12](2)
+		 * GPY6[5]	EBI_DATA[13](2)
+		 * GPY6[6]	EBI_DATA[14](2)
+		 * GPY6[7]	EBI_DATA[15](2)
+		 */
+		for (i = 0; i < 8; i++) {
+			gpio_cfg_pin(GPIO_Y30 + i, 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 (flags & PINMUX_FLAG_16BIT) {
+				gpio_cfg_pin(GPIO_Y60 + i, GPIO_FUNC(2));
+				gpio_set_pull(GPIO_Y60 + i,
+					      GPIO_PULL_UP);
+			}
+		}
+		break;
+	case PERIPH_ID_SPI0:
+	case PERIPH_ID_SPI1:
+	case PERIPH_ID_SPI2:
+	case PERIPH_ID_SPI3: {
+		int cfg;
+
+		switch (peripheral) {
+		default:
+		case PERIPH_ID_SPI0:
+			start = GPIO_A20;
+			cfg = 0x2;
+			break;
+		case PERIPH_ID_SPI1:
+			start = GPIO_A24;
+			cfg = 0x2;
+			break;
+		case PERIPH_ID_SPI2:
+			start = GPIO_B11;
+			cfg = 0x5;
+			break;
+		case PERIPH_ID_SPI3:
+			start = GPIO_E00;
+			cfg = 0x2;
+			break;
+		}
+
+		for (i = 0; i < 4; i++)
+			gpio_cfg_pin(start + i, GPIO_FUNC(cfg));
+		break;
+	}
+	case PERIPH_ID_SPI4:
+		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));
+		break;
+	case PERIPH_ID_BACKLIGHT:
+		gpio_cfg_pin(GPIO_B20, GPIO_OUTPUT);
+		gpio_set_value(GPIO_B20, 1);
+		break;
+	case PERIPH_ID_LCD:
+		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);
+		break;
+	case PERIPH_ID_I2C0:
+		gpio_cfg_pin(GPIO_B30, GPIO_FUNC(0x2));
+		gpio_cfg_pin(GPIO_B31, GPIO_FUNC(0x2));
+		gpio_set_pull(GPIO_B30, GPIO_PULL_NONE);
+		gpio_set_pull(GPIO_B31, GPIO_PULL_NONE);
+		break;
+	case PERIPH_ID_I2C1:
+		gpio_cfg_pin(GPIO_B32, GPIO_FUNC(0x2));
+		gpio_cfg_pin(GPIO_B33, GPIO_FUNC(0x2));
+		gpio_set_pull(GPIO_B32, GPIO_PULL_NONE);
+		gpio_set_pull(GPIO_B33, GPIO_PULL_NONE);
+		break;
+	case PERIPH_ID_I2C2:
+		gpio_cfg_pin(GPIO_A06, GPIO_FUNC(0x3));
+		gpio_cfg_pin(GPIO_A07, GPIO_FUNC(0x3));
+		gpio_set_pull(GPIO_A06, GPIO_PULL_NONE);
+		gpio_set_pull(GPIO_A07, GPIO_PULL_NONE);
+		break;
+	case PERIPH_ID_I2C3:
+		gpio_cfg_pin(GPIO_A12, GPIO_FUNC(0x3));
+		gpio_cfg_pin(GPIO_A13, GPIO_FUNC(0x3));
+		gpio_set_pull(GPIO_A12, GPIO_PULL_NONE);
+		gpio_set_pull(GPIO_A13, GPIO_PULL_NONE);
+		break;
+	case PERIPH_ID_I2C4:
+		gpio_cfg_pin(GPIO_A20, GPIO_FUNC(0x3));
+		gpio_cfg_pin(GPIO_A21, GPIO_FUNC(0x3));
+		gpio_set_pull(GPIO_A20, GPIO_PULL_NONE);
+		gpio_set_pull(GPIO_A21, GPIO_PULL_NONE);
+		break;
+	case PERIPH_ID_I2C5:
+		gpio_cfg_pin(GPIO_A22, GPIO_FUNC(0x3));
+		gpio_cfg_pin(GPIO_A23, GPIO_FUNC(0x3));
+		gpio_set_pull(GPIO_A22, GPIO_PULL_NONE);
+		gpio_set_pull(GPIO_A23, GPIO_PULL_NONE);
+		break;
+	case PERIPH_ID_I2C6:
+		gpio_cfg_pin(GPIO_B13, GPIO_FUNC(0x4));
+		gpio_cfg_pin(GPIO_B14, GPIO_FUNC(0x4));
+		break;
+	case PERIPH_ID_I2C7:
+		gpio_cfg_pin(GPIO_B22, GPIO_FUNC(0x3));
+		gpio_cfg_pin(GPIO_B23, GPIO_FUNC(0x3));
+		gpio_set_pull(GPIO_B22, GPIO_PULL_NONE);
+		gpio_set_pull(GPIO_B23, GPIO_PULL_NONE);
+		break;
+	case PERIPH_ID_DPHPD:
+		/* 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);
+		break;
+	case PERIPH_ID_I2S1:
+		for (i = 0; i < 5; i++)
+			gpio_cfg_pin(GPIO_B00 + i, GPIO_FUNC(0x02));
+		break;
+	default:
+		printk(BIOS_DEBUG, "%s: invalid peripheral %d", __func__, peripheral);
+		return -1;
+	}
+
+	return 0;
+}
diff --git a/src/cpu/samsung/exynos5420/pinmux.h b/src/cpu/samsung/exynos5420/pinmux.h
new file mode 100644
index 0000000..c94b6eb
--- /dev/null
+++ b/src/cpu/samsung/exynos5420/pinmux.h
@@ -0,0 +1,55 @@
+/*
+ * 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_EXYNOS5420_PINMUX_H
+#define CPU_SAMSUNG_EXYNOS5420_PINMUX_H
+
+#include "periph.h"
+
+enum {
+	PINMUX_FLAG_NONE	= 0x00000000,
+
+	/* Flags for eMMC */
+	PINMUX_FLAG_8BIT_MODE	= 1 << 0,	/* SDMMC 8-bit mode */
+
+	/*
+	 * Flags for SPI.
+	 */
+	PINMUX_FLAG_SLAVE_MODE	= 1 << 0,	/* Slave mode */
+
+	/* Flags for SROM controller */
+	PINMUX_FLAG_BANK	= 3 << 0,	/* bank number (0-3) */
+	PINMUX_FLAG_16BIT	= 1 << 2,	/* 16-bit width */
+};
+
+/**
+ * Configures the pinmux for a particular peripheral.
+ *
+ * Each gpio can be configured in many different ways (4 bits on exynos)
+ * such as "input", "output", "special function", "external interrupt"
+ * etc. This function will configure the peripheral pinmux along with
+ * pull-up/down and drive strength.
+ *
+ * @param peripheral	peripheral to be configured
+ * @param flags		configure flags
+ * @return 0 if ok, -1 on error (e.g. unsupported peripheral)
+ */
+int exynos_pinmux_config(enum periph_id peripheral, int flags);
+
+#endif
diff --git a/src/cpu/samsung/exynos5420/power.c b/src/cpu/samsung/exynos5420/power.c
new file mode 100644
index 0000000..029efc9
--- /dev/null
+++ b/src/cpu/samsung/exynos5420/power.c
@@ -0,0 +1,138 @@
+/*
+ * 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 <console/console.h>
+#include <arch/io.h>
+#include <arch/hlt.h>
+#include "cpu.h"
+#include "power.h"
+#include "sysreg.h"
+
+static void ps_hold_setup(void)
+{
+	struct exynos5_power *power =
+		samsung_get_base_power();
+
+	/* Set PS-Hold high */
+	setbits_le32(&power->ps_hold_ctrl, POWER_PS_HOLD_CONTROL_DATA_HIGH);
+}
+
+void power_reset(void)
+{
+	struct exynos5_power *power =
+		samsung_get_base_power();
+
+	/* Clear inform1 so there's no change we think we've got a wake reset */
+	power->inform1 = 0;
+
+	setbits_le32(&power->sw_reset, 1);
+}
+
+/* This function never returns */
+void power_shutdown(void)
+{
+	struct exynos5_power *power =
+		samsung_get_base_power();
+
+	clrbits_le32(&power->ps_hold_ctrl, POWER_PS_HOLD_CONTROL_DATA_HIGH);
+
+	hlt();
+}
+
+void power_enable_dp_phy(void)
+{
+	struct exynos5_power *power =
+		samsung_get_base_power();
+
+	setbits_le32(&power->dptx_phy_control, DPTX_PHY_ENABLE);
+}
+
+void power_enable_usb_phy(void)
+{
+	struct exynos5_sysreg *sysreg =
+		samsung_get_base_sysreg();
+	struct exynos5_power *power =
+		samsung_get_base_power();
+	unsigned int phy_cfg;
+
+	/* Setting USB20PHY_CONFIG register to USB 2.0 HOST link */
+	phy_cfg = readl(&sysreg->usb20_phy_cfg);
+	if (phy_cfg & USB20_PHY_CFG_EN) {
+		printk(BIOS_DEBUG, "USB 2.0 HOST link already selected\n");
+	} else {
+		phy_cfg |= USB20_PHY_CFG_EN;
+		writel(phy_cfg, &sysreg->usb20_phy_cfg);
+	}
+
+	/* Enabling USBHOST_PHY */
+	setbits_le32(&power->usb_host_phy_ctrl, POWER_USB_HOST_PHY_CTRL_EN);
+}
+
+void power_disable_usb_phy(void)
+{
+	struct exynos5_power *power =
+		samsung_get_base_power();
+
+	/* Disabling USBHost_PHY */
+	clrbits_le32(&power->usb_host_phy_ctrl, POWER_USB_HOST_PHY_CTRL_EN);
+}
+
+void power_enable_hw_thermal_trip(void)
+{
+	struct exynos5_power *power =
+		samsung_get_base_power();
+
+	/* Enable HW thermal trip */
+	setbits_le32(&power->ps_hold_ctrl, POWER_ENABLE_HW_TRIP);
+}
+
+uint32_t power_read_reset_status(void)
+{
+	struct exynos5_power *power =
+		samsung_get_base_power();
+
+	return power->inform1;
+}
+
+void power_exit_wakeup(void)
+{
+	struct exynos5_power *power =
+		samsung_get_base_power();
+	typedef void (*resume_func)(void);
+
+	((resume_func)power->inform0)();
+}
+
+int power_init(void)
+{
+	ps_hold_setup();
+	return 0;
+}
+
+void power_enable_xclkout(void)
+{
+	struct exynos5_power *power =
+		samsung_get_base_power();
+
+	/* use xxti for xclk out */
+	clrsetbits_le32(&power->pmu_debug, PMU_DEBUG_CLKOUT_SEL_MASK,
+				PMU_DEBUG_XXTI);
+}
diff --git a/src/cpu/samsung/exynos5420/power.h b/src/cpu/samsung/exynos5420/power.h
new file mode 100644
index 0000000..3c019d6
--- /dev/null
+++ b/src/cpu/samsung/exynos5420/power.h
@@ -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
+ */
+
+/* Register map for Exynos5 PMU */
+
+#ifndef CPU_SAMSUNG_EXYNOS5420_POWER_H
+#define CPU_SAMSUNG_EXYNOS5420_POWER_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_HOST_PHY_CTRL_EN		(1 << 0)
+#define POWER_PS_HOLD_CONTROL_DATA_HIGH		(1 << 8)
+#define POWER_ENABLE_HW_TRIP			(1UL << 31)
+
+#define DPTX_PHY_ENABLE		(1 << 0)
+
+/* PMU_DEBUG bits [12:8] = 0x1000 selects XXTI clock source */
+#define PMU_DEBUG_XXTI                          0x1000
+/* Mask bit[12:8] for xxti clock selection */
+#define PMU_DEBUG_CLKOUT_SEL_MASK               0x1f00
+
+/* Power Management Unit register map */
+struct exynos5_power {
+	/* Add registers as and when required */
+	uint8_t		reserved1[0x0400];
+	uint32_t	sw_reset;		/* 0x0400 */
+	uint8_t		reserved2[0x0304];
+	uint32_t	usb_host_phy_ctrl;	/* 0x0708 */
+	uint8_t		reserved3[0x8];
+	uint32_t	mipi_phy1_control;	/* 0x0714 */
+	uint8_t		reserved4[0x8];
+	uint32_t	dptx_phy_control;	/* 0x0720 */
+	uint8_t		reserved5[0xdc];
+	uint32_t	inform0;		/* 0x0800 */
+	uint32_t	inform1;		/* 0x0804 */
+	uint8_t		reserved6[0x1f8];
+	uint32_t	pmu_debug;		/* 0x0A00*/
+	uint8_t         reserved7[0x2908];
+	uint32_t	ps_hold_ctrl;		/* 0x330c */
+} __attribute__ ((__packed__));
+
+/**
+ * Perform a software reset.
+ */
+void power_reset(void);
+
+/**
+ * Power off the system; it should never return.
+ */
+void power_shutdown(void);
+
+/* Enable DPTX PHY */
+void power_enable_dp_phy(void);
+
+void power_enable_usb_phy(void);
+void power_disable_usb_phy(void);
+
+/* Initialize the pmic voltages to power up the system */
+int power_init(void);
+
+/* Read the reset status. */
+uint32_t power_read_reset_status(void);
+
+/* Read the resume function and call it. */
+void power_exit_wakeup(void);
+
+/* pmu debug is used for xclkout, enable xclkout with source as XXTI */
+void power_enable_xclkout(void);
+
+#endif
diff --git a/src/cpu/samsung/exynos5420/pwm.c b/src/cpu/samsung/exynos5420/pwm.c
new file mode 100644
index 0000000..34fc2b1
--- /dev/null
+++ b/src/cpu/samsung/exynos5420/pwm.c
@@ -0,0 +1,191 @@
+/*
+ * This file is part of the coreboot project.
+ *
+ * Copyright (C) 2011 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 "clk.h"
+#include "cpu.h"
+#include "periph.h"
+#include "pwm.h"
+
+int pwm_enable(int pwm_id)
+{
+	const struct s5p_timer *pwm =
+			samsung_get_base_timer();
+	unsigned long tcon;
+
+	tcon = readl(&pwm->tcon);
+	tcon |= TCON_START(pwm_id);
+
+	writel(tcon, &pwm->tcon);
+
+	return 0;
+}
+
+int pwm_check_enabled(int pwm_id)
+{
+	const struct s5p_timer *pwm =
+			samsung_get_base_timer();
+	const unsigned long tcon = readl(&pwm->tcon);
+
+	return tcon & TCON_START(pwm_id);
+}
+
+void pwm_disable(int pwm_id)
+{
+	const struct s5p_timer *pwm =
+			samsung_get_base_timer();
+	unsigned long tcon;
+
+	tcon = readl(&pwm->tcon);
+	tcon &= ~TCON_START(pwm_id);
+
+	writel(tcon, &pwm->tcon);
+}
+
+static unsigned long pwm_calc_tin(int pwm_id, unsigned long freq)
+{
+	unsigned long tin_parent_rate;
+	unsigned int div;
+
+	tin_parent_rate = clock_get_periph_rate(PERIPH_ID_PWM0);
+
+	for (div = 2; div <= 16; div *= 2) {
+		if ((tin_parent_rate / (div << 16)) < freq)
+			return tin_parent_rate / div;
+	}
+
+	return tin_parent_rate / 16;
+}
+
+#define NS_IN_SEC 1000000000UL
+
+int pwm_config(int pwm_id, int duty_ns, int period_ns)
+{
+	const struct s5p_timer *pwm =
+			samsung_get_base_timer();
+	unsigned int offset;
+	unsigned long tin_rate;
+	unsigned long tin_ns;
+	unsigned long frequency;
+	unsigned long tcon;
+	unsigned long tcnt;
+	unsigned long tcmp;
+
+	/*
+	 * We currently avoid using 64bit arithmetic by using the
+	 * fact that anything faster than 1GHz is easily representable
+	 * by 32bits.
+	 */
+	if (period_ns > NS_IN_SEC || duty_ns > NS_IN_SEC || period_ns == 0)
+		return -1;
+
+	if (duty_ns > period_ns)
+		return -1;
+
+	frequency = NS_IN_SEC / period_ns;
+
+	/* Check to see if we are changing the clock rate of the PWM */
+	tin_rate = pwm_calc_tin(pwm_id, frequency);
+
+	tin_ns = NS_IN_SEC / tin_rate;
+	tcnt = period_ns / tin_ns;
+
+	/* Note, counters count down */
+	tcmp = duty_ns / tin_ns;
+	tcmp = tcnt - tcmp;
+
+	/* Update the PWM register block. */
+	offset = pwm_id * 3;
+	if (pwm_id < 4) {
+		writel(tcnt, &pwm->tcntb0 + offset);
+		writel(tcmp, &pwm->tcmpb0 + offset);
+	}
+
+	tcon = readl(&pwm->tcon);
+	tcon |= TCON_UPDATE(pwm_id);
+	if (pwm_id < 4)
+		tcon |= TCON_AUTO_RELOAD(pwm_id);
+	else
+		tcon |= TCON4_AUTO_RELOAD;
+	writel(tcon, &pwm->tcon);
+
+	tcon &= ~TCON_UPDATE(pwm_id);
+	writel(tcon, &pwm->tcon);
+
+	return 0;
+}
+
+int pwm_init(int pwm_id, int div, int invert)
+{
+	u32 val;
+	const struct s5p_timer *pwm =
+			samsung_get_base_timer();
+	unsigned long ticks_per_period;
+	unsigned int offset, prescaler;
+
+	/*
+	 * Timer Freq(HZ) =
+	 *	PWM_CLK / { (prescaler_value + 1) * (divider_value) }
+	 */
+
+	val = readl(&pwm->tcfg0);
+	if (pwm_id < 2) {
+		prescaler = PRESCALER_0;
+		val &= ~0xff;
+		val |= (prescaler & 0xff);
+	} else {
+		prescaler = PRESCALER_1;
+		val &= ~(0xff << 8);
+		val |= (prescaler & 0xff) << 8;
+	}
+	writel(val, &pwm->tcfg0);
+	val = readl(&pwm->tcfg1);
+	val &= ~(0xf << MUX_DIV_SHIFT(pwm_id));
+	val |= (div & 0xf) << MUX_DIV_SHIFT(pwm_id);
+	writel(val, &pwm->tcfg1);
+
+
+	if (pwm_id == 4) {
+		/*
+		 * TODO(sjg): Use this as a countdown timer for now. We count
+		 * down from the maximum value to 0, then reset.
+		 */
+		ticks_per_period = -1UL;
+	} else {
+		const unsigned long pwm_hz = 1000;
+		unsigned long timer_rate_hz = clock_get_periph_rate(
+			PERIPH_ID_PWM0) / ((prescaler + 1) * (1 << div));
+
+		ticks_per_period = timer_rate_hz / pwm_hz;
+	}
+
+	/* set count value */
+	offset = pwm_id * 3;
+
+	writel(ticks_per_period, &pwm->tcntb0 + offset);
+
+	val = readl(&pwm->tcon) & ~(0xf << TCON_OFFSET(pwm_id));
+	if (invert && (pwm_id < 4))
+		val |= TCON_INVERTER(pwm_id);
+	writel(val, &pwm->tcon);
+
+	pwm_enable(pwm_id);
+
+	return 0;
+}
diff --git a/src/cpu/samsung/exynos5420/pwm.h b/src/cpu/samsung/exynos5420/pwm.h
new file mode 100644
index 0000000..4300061
--- /dev/null
+++ b/src/cpu/samsung/exynos5420/pwm.h
@@ -0,0 +1,70 @@
+/*
+ * 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
+ */
+
+#ifndef CPU_SAMSUNG_EXYNOS5420_PWM_H
+#define CPU_SAMSUNG_EXYNOS5420_PWM_H
+
+#define PRESCALER_0		(8 - 1)		/* prescaler of timer 0, 1 */
+#define PRESCALER_1		(16 - 1)	/* prescaler of timer 2, 3, 4 */
+
+/* Divider MUX */
+#define MUX_DIV_1		0		/* 1/1 period */
+#define MUX_DIV_2		1		/* 1/2 period */
+#define MUX_DIV_4		2		/* 1/4 period */
+#define MUX_DIV_8		3		/* 1/8 period */
+#define MUX_DIV_16		4		/* 1/16 period */
+
+#define MUX_DIV_SHIFT(x)	(x * 4)
+
+#define TCON_OFFSET(x)		((x + 1) * (!!x) << 2)
+
+#define TCON_START(x)		(1 << TCON_OFFSET(x))
+#define TCON_UPDATE(x)		(1 << (TCON_OFFSET(x) + 1))
+#define TCON_INVERTER(x)	(1 << (TCON_OFFSET(x) + 2))
+#define TCON_AUTO_RELOAD(x)	(1 << (TCON_OFFSET(x) + 3))
+#define TCON4_AUTO_RELOAD	(1 << 22)
+
+struct s5p_timer {
+	unsigned int	tcfg0;
+	unsigned int	tcfg1;
+	unsigned int	tcon;
+	unsigned int	tcntb0;
+	unsigned int	tcmpb0;
+	unsigned int	tcnto0;
+	unsigned int	tcntb1;
+	unsigned int	tcmpb1;
+	unsigned int	tcnto1;
+	unsigned int	tcntb2;
+	unsigned int	tcmpb2;
+	unsigned int	tcnto2;
+	unsigned int	tcntb3;
+	unsigned int	tcmpb3;
+	unsigned int	tcnto3;
+	unsigned int	tcntb4;
+	unsigned int	tcnto4;
+	unsigned int	tintcstat;
+};
+
+int pwm_config(int pwm_id, int duty_ns, int period_ns);
+int pwm_check_enabled(int pwm_id);
+void pwm_disable(int pwm_id);
+int pwm_enable(int pwm_id);
+int pwm_init(int pwm_id, int div, int invert);
+
+#endif
diff --git a/src/cpu/samsung/exynos5420/reset.c b/src/cpu/samsung/exynos5420/reset.c
new file mode 100644
index 0000000..78571ba
--- /dev/null
+++ b/src/cpu/samsung/exynos5420/reset.c
@@ -0,0 +1,26 @@
+/*
+ * 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 <reset.h>
+#include <arch/io.h>
+
+void soft_reset(void)
+{
+	writel(0x1, samsung_get_base_swreset());
+}
diff --git a/src/cpu/samsung/exynos5420/setup.h b/src/cpu/samsung/exynos5420/setup.h
new file mode 100644
index 0000000..7a779ba
--- /dev/null
+++ b/src/cpu/samsung/exynos5420/setup.h
@@ -0,0 +1,753 @@
+/*
+ * 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 SMDK5420 board based on Exynos5 */
+
+#ifndef CPU_SAMSUNG_EXYNOS5420_SETUP_H
+#define CPU_SAMSUNG_EXYNOS5420_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
+
+/* 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	(1 << 0)
+#define LPDDR3PHY_CTRL_PHY_RESET_OFF	(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 resyncronization */
+
+/* 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 encourter 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/cpu/samsung/exynos5420/spi.c b/src/cpu/samsung/exynos5420/spi.c
new file mode 100644
index 0000000..503cee9
--- /dev/null
+++ b/src/cpu/samsung/exynos5420/spi.c
@@ -0,0 +1,222 @@
+/*
+ * 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 <console/console.h>
+#include <arch/io.h>
+#include <stdlib.h>
+#include <assert.h>
+#include "gpio.h"
+#include "clk.h"
+#include "spi.h"
+
+#define OM_STAT		(0x1f << 1)
+#define EXYNOS_BASE_SPI1 ((void *)0x12d30000)
+
+#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 currrent 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(&regs->ch_cfg, SPI_CH_RST);
+	clrbits_le32(&regs->ch_cfg, SPI_CH_RST);
+	writel(((todo * 8) / 32) | SPI_PACKET_CNT_EN, &regs->pkt_cnt);
+
+	while (in_bytes) {
+		uint32_t spi_sts;
+		int temp;
+
+		spi_sts = readl(&regs->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, &regs->tx_data);
+			out_bytes -= 4;
+			tx_lvl += 4;
+		}
+		while (rx_lvl >= 4 && in_bytes) {
+			temp = readl(&regs->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, &regs->pkt_cnt);
+	/* set FB_CLK_SEL */
+	writel(SPI_FB_DELAY_180, &regs->fb_clk);
+	/* set CH_WIDTH and BUS_WIDTH as word */
+	setbits_le32(&regs->mode_cfg,
+		     SPI_MODE_CH_WIDTH_WORD | SPI_MODE_BUS_WIDTH_WORD);
+	clrbits_le32(&regs->ch_cfg, SPI_CH_CPOL_L); /* CPOL: active high */
+
+	/* clear rx and tx channel if set priveously */
+	clrbits_le32(&regs->ch_cfg, SPI_RX_CH_ON | SPI_TX_CH_ON);
+
+	setbits_le32(&regs->swap_cfg,
+		     SPI_RX_SWAP_EN | SPI_RX_BYTE_SWAP | SPI_RX_HWORD_SWAP);
+
+	/* do a soft reset */
+	setbits_le32(&regs->ch_cfg, SPI_CH_RST);
+	clrbits_le32(&regs->ch_cfg, SPI_CH_RST);
+
+	/* now set rx and tx channel ON */
+	setbits_le32(&regs->ch_cfg, SPI_RX_CH_ON | SPI_TX_CH_ON | SPI_CH_HS_EN);
+	clrbits_le32(&regs->cs_reg, SPI_SLAVE_SIG_INACT); /* CS low */
+	return 0;
+}
+
+int exynos_spi_read(struct exynos_spi *regs, void *dest, u32 len, u32 off)
+{
+	int upto, todo;
+	int i;
+	/* Send read instruction (0x3h) followed by a 24 bit addr */
+	writel((SF_READ_DATA_CMD << 24) | off, &regs->tx_data);
+
+	/* waiting for TX done */
+	while (!(readl(&regs->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(&regs->cs_reg, SPI_SLAVE_SIG_INACT);/* make the CS high */
+
+	/*
+	 * Let put controller mode to BYTE as
+	 * SPI driver does not support WORD mode yet
+	 */
+	clrbits_le32(&regs->mode_cfg,
+		     SPI_MODE_CH_WIDTH_WORD | SPI_MODE_BUS_WIDTH_WORD);
+	writel(0, &regs->swap_cfg);
+
+	return len;
+}
+
+int exynos_spi_close(struct exynos_spi *regs)
+{
+	/*
+	 * Flush spi tx, rx fifos and reset the SPI controller
+	 * and clear rx/tx channel
+	 */
+	clrsetbits_le32(&regs->ch_cfg, SPI_CH_HS_EN, SPI_CH_RST);
+	clrbits_le32(&regs->ch_cfg, SPI_CH_RST);
+	clrbits_le32(&regs->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 = EXYNOS_BASE_SPI1;
+	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;
+}
+
+int init_default_cbfs_media(struct cbfs_media *media) {
+	return initialize_exynos_spi_cbfs_media(
+			media,
+			(void*)CONFIG_CBFS_CACHE_ADDRESS,
+			CONFIG_CBFS_CACHE_SIZE);
+}
diff --git a/src/cpu/samsung/exynos5420/spi.h b/src/cpu/samsung/exynos5420/spi.h
new file mode 100644
index 0000000..faf82b0
--- /dev/null
+++ b/src/cpu/samsung/exynos5420/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_EXYNOS5420_SPI_H
+#define CPU_SAMSUNG_EXYNOS5420_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/cpu/samsung/exynos5420/sysreg.h b/src/cpu/samsung/exynos5420/sysreg.h
new file mode 100644
index 0000000..3af95d2
--- /dev/null
+++ b/src/cpu/samsung/exynos5420/sysreg.h
@@ -0,0 +1,37 @@
+/*
+ * 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_EXYNOS5420_SYSREG_H
+#define CPU_SAMSUNG_EXYNOS5420_SYSREG_H
+
+/* sysreg map */
+struct exynos5_sysreg {
+	/* Add registers as and when required */
+	unsigned char	res1[0x214];
+	unsigned int	disp1blk_cfg;
+	unsigned char	res2[0x18];
+	unsigned int	usb20_phy_cfg;
+};
+
+#define FIMDBYPASS_DISP1	(1 << 15)
+#define USB20_PHY_CFG_EN	(1 << 0)
+
+#endif
diff --git a/src/cpu/samsung/exynos5420/timer.c b/src/cpu/samsung/exynos5420/timer.c
new file mode 100644
index 0000000..405effa
--- /dev/null
+++ b/src/cpu/samsung/exynos5420/timer.c
@@ -0,0 +1,110 @@
+/*
+ * 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 <arch/io.h>
+#include <timer.h>
+#include <delay.h>
+#include "timer.h"
+#include "pwm.h"
+#include "clk.h"
+#include "cpu.h"
+
+static unsigned long long timer_reset_value;
+static unsigned long lastinc;
+
+/* macro to read the 16 bit timer */
+static inline struct s5p_timer *s5p_get_base_timer(void)
+{
+	return samsung_get_base_timer();
+}
+
+/**
+ * Read the countdown timer.
+ *
+ * This operates at 1MHz and counts downwards. It will wrap about every
+ * hour (2^32 microseconds).
+ *
+ * @return current value of timer
+ */
+static unsigned long timer_get_us_down(void)
+{
+	struct s5p_timer *const timer = s5p_get_base_timer();
+
+	return readl(&timer->tcnto4);
+}
+
+void init_timer(void)
+{
+	/* Timer may have been enabled in SPL */
+	if (!pwm_check_enabled(4)) {
+		/* PWM Timer 4 */
+		pwm_init(4, MUX_DIV_4, 0);
+		pwm_config(4, 100000, 100000);
+		pwm_enable(4);
+
+		/* Use this as the current monotonic time in us */
+		timer_reset_value = 0;
+
+		/* Use this as the last timer value we saw */
+		lastinc = timer_get_us_down();
+	}
+}
+
+/*
+ * timer without interrupts
+ */
+unsigned long get_timer(unsigned long base)
+{
+	unsigned long now = timer_get_us_down();
+
+	/*
+	 * Increment the time by the amount elapsed since the last read.
+	 * The timer may have wrapped around, but it makes no difference to
+	 * our arithmetic here.
+	 */
+	timer_reset_value += lastinc - now;
+	lastinc = now;
+
+	/* Divide by 1000 to convert from us to ms */
+	return timer_reset_value / 1000 - base;
+}
+
+/* delay x useconds */
+void udelay(unsigned usec)
+{
+	struct mono_time current, end;
+
+	timer_monotonic_get(&current);
+	end = current;
+	mono_time_add_usecs(&end, usec);
+
+	if (mono_time_after(&current, &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(&current, &end))
+		timer_monotonic_get(&current);
+}
+
diff --git a/src/cpu/samsung/exynos5420/timer.h b/src/cpu/samsung/exynos5420/timer.h
new file mode 100644
index 0000000..f02d58a
--- /dev/null
+++ b/src/cpu/samsung/exynos5420/timer.h
@@ -0,0 +1,25 @@
+/*
+ * 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_EXYNOS5420_TIMER_H
+#define CPU_SAMSUNG_EXYNOS5420_TIMER_H
+
+unsigned long get_timer(unsigned long base);
+
+#endif
diff --git a/src/cpu/samsung/exynos5420/tmu.c b/src/cpu/samsung/exynos5420/tmu.c
new file mode 100644
index 0000000..1b04b6c
--- /dev/null
+++ b/src/cpu/samsung/exynos5420/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 exynos5420_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 temperatue,
+ * get current temperatue.
+ *
+ * @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(&reg->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, &reg->triminfo_control);
+
+	/* Get the compensation parameter */
+	te_temp = readl(&reg->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, &reg->threshold_temp_rise);
+	writel(cooling_temp, &reg->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, &reg->tmu_control);
+
+	writel(INTCLEARALL, &reg->intclear);
+	/* TMU core enable */
+	con = readl(&reg->tmu_control);
+	con |= (info->tmu_mux << 20) | THERM_TRIP_EN | CORE_EN;
+
+	writel(con, &reg->tmu_control);
+
+	/* Enable HW thermal trip */
+	power_enable_hw_thermal_trip();
+
+	/* LEV1 LEV2 interrupt enable */
+	writel(INTEN_RISE1 | INTEN_RISE2, &reg->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/cpu/samsung/exynos5420/tmu.h b/src/cpu/samsung/exynos5420/tmu.h
new file mode 100644
index 0000000..cf81b9a
--- /dev/null
+++ b/src/cpu/samsung/exynos5420/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_EXYNOS5420_TMU_H
+#define CPU_SAMSUNG_EXYNOS5420_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,
+};
+
+/* Tmeperature 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_EXYNOS5420_TMU_H */
diff --git a/src/cpu/samsung/exynos5420/uart.c b/src/cpu/samsung/exynos5420/uart.c
new file mode 100644
index 0000000..2dea033
--- /dev/null
+++ b/src/cpu/samsung/exynos5420/uart.c
@@ -0,0 +1,200 @@
+/*
+ * 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>	/* for __console definition */
+#include <uart.h>
+#include <arch/io.h>
+#include "uart.h"
+#include "clk.h"
+#include "cpu.h"
+
+#define RX_FIFO_COUNT_MASK	0xff
+#define RX_FIFO_FULL_MASK	(1 << 8)
+#define TX_FIFO_FULL_MASK	(1 << 24)
+
+/* FIXME(dhendrix): exynos5 has 4 UARTs and its functions in u-boot take a
+   base_port argument. However console_driver functions do not. */
+static uint32_t base_port = CONFIG_CONSOLE_SERIAL_UART_ADDRESS;
+
+/*
+ * The coefficient, used to calculate the baudrate on S5P UARTs is
+ * calculated as
+ * C = UBRDIV * 16 + number_of_set_bits_in_UDIVSLOT
+ * however, section 31.6.11 of the datasheet doesn't recomment using 1 for 1,
+ * 3 for 2, ... (2^n - 1) for n, instead, they suggest using these constants:
+ */
+static const int udivslot[] = {
+	0,
+	0x0080,
+	0x0808,
+	0x0888,
+	0x2222,
+	0x4924,
+	0x4a52,
+	0x54aa,
+	0x5555,
+	0xd555,
+	0xd5d5,
+	0xddd5,
+	0xdddd,
+	0xdfdd,
+	0xdfdf,
+	0xffdf,
+};
+
+static void serial_setbrg_dev(void)
+{
+	struct s5p_uart *uart = (struct s5p_uart *)base_port;
+	u32 uclk;
+	u32 baudrate = CONFIG_TTYS0_BAUD;
+	u32 val;
+
+	// All UARTs share the same clock.
+	uclk = clock_get_periph_rate(PERIPH_ID_UART3);
+	val = uclk / baudrate;
+
+	writel(val / 16 - 1, &uart->ubrdiv);
+
+	/*
+	 * FIXME(dhendrix): the original uart.h had a "br_rest" value which
+	 * does not seem relevant to the exynos5420... 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(void)
+{
+	struct s5p_uart *uart = (struct s5p_uart *)base_port;
+
+	// TODO initialize with correct peripheral id by base_port.
+	exynos_pinmux_config(PERIPH_ID_UART3, PINMUX_FLAG_NONE);
+
+	/* enable FIFOs */
+	writel(0x1, &uart->ufcon);
+	writel(0, &uart->umcon);
+	/* 8N1 */
+	writel(0x3, &uart->ulcon);
+	/* No interrupts, no DMA, pure polling */
+	writel(0x245, &uart->ucon);
+
+	serial_setbrg_dev();
+}
+
+static int exynos5_uart_err_check(int op)
+{
+	struct s5p_uart *uart = (struct s5p_uart *)base_port;
+	unsigned int mask;
+
+	/*
+	 * UERSTAT
+	 * Break Detect	[3]
+	 * Frame Err	[2] : receive operation
+	 * Parity Err	[1] : receive operation
+	 * Overrun Err	[0] : receive operation
+	 */
+	if (op)
+		mask = 0x8;
+	else
+		mask = 0xf;
+
+	return readl(&uart->uerstat) & mask;
+}
+
+/*
+ * Read a single byte from the serial port. Returns 1 on success, 0
+ * otherwise. When the function is succesfull, the character read is
+ * written into its argument c.
+ */
+static unsigned char exynos5_uart_rx_byte(void)
+{
+	struct s5p_uart *uart = (struct s5p_uart *)base_port;
+
+	/* wait for character to arrive */
+	while (!(readl(&uart->ufstat) & (RX_FIFO_COUNT_MASK |
+					 RX_FIFO_FULL_MASK))) {
+		if (exynos5_uart_err_check(0))
+			return 0;
+	}
+
+	return readb(&uart->urxh) & 0xff;
+}
+
+/*
+ * Output a single byte to the serial port.
+ */
+static void exynos5_uart_tx_byte(unsigned char data)
+{
+	struct s5p_uart *uart = (struct s5p_uart *)base_port;
+
+	/* wait for room in the tx FIFO */
+	while ((readl(&uart->ufstat) & TX_FIFO_FULL_MASK)) {
+		if (exynos5_uart_err_check(1))
+			return;
+	}
+
+	writeb(data, &uart->utxh);
+}
+
+#if !defined(__PRE_RAM__)
+
+static const struct console_driver exynos5_uart_console __console = {
+	.init     = exynos5_init_dev,
+	.tx_byte  = exynos5_uart_tx_byte,
+//	.tx_flush = exynos5_uart_tx_flush,
+	.rx_byte  = exynos5_uart_rx_byte,
+//	.tst_byte = exynos5_uart_tst_byte,
+};
+
+uint32_t uartmem_getbaseaddr(void)
+{
+	return base_port;
+}
+
+#else
+
+void uart_init(void)
+{
+	exynos5_init_dev();
+}
+
+unsigned char uart_rx_byte(void)
+{
+	return exynos5_uart_rx_byte();
+}
+
+void uart_tx_byte(unsigned char data)
+{
+	exynos5_uart_tx_byte(data);
+}
+
+void uart_tx_flush(void)
+{
+}
+
+#endif
diff --git a/src/cpu/samsung/exynos5420/uart.h b/src/cpu/samsung/exynos5420/uart.h
new file mode 100644
index 0000000..dcf9ed7
--- /dev/null
+++ b/src/cpu/samsung/exynos5420/uart.h
@@ -0,0 +1,54 @@
+/*
+ * 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_EXYNOS5420_UART_H
+#define CPU_SAMSUNG_EXYNOS5420_UART_H
+
+#define EXYNOS5_UART0_BASE	0x12c00000
+#define EXYNOS5_UART1_BASE	0x12c10000
+#define EXYNOS5_UART2_BASE	0x12c20000
+#define EXYNOS5_UART3_BASE	0x12c30000
+#define EXYNOS5_ISP_UART_BASE	0x13190000
+
+/* 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/cpu/samsung/exynos5420/wakeup.c b/src/cpu/samsung/exynos5420/wakeup.c
new file mode 100644
index 0000000..5764c83
--- /dev/null
+++ b/src/cpu/samsung/exynos5420/wakeup.c
@@ -0,0 +1,50 @@
+/*
+ * 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. */
+	die("Failed to wake up.\n");
+}
+
+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;
+}
diff --git a/src/cpu/samsung/exynos5420/wakeup.h b/src/cpu/samsung/exynos5420/wakeup.h
new file mode 100644
index 0000000..2658875
--- /dev/null
+++ b/src/cpu/samsung/exynos5420/wakeup.h
@@ -0,0 +1,42 @@
+/*
+ * 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_EXYNOS5420_WAKEUP_H
+#define CPU_SAMSUNG_EXYNOS5420_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);
+
+#endif	/* CPU_SAMSUNG_EXYNOS5420_WAKEUP_H */
diff --git a/src/mainboard/google/snow/Kconfig b/src/mainboard/google/snow/Kconfig
index 3ebaa58..91bd66d 100644
--- a/src/mainboard/google/snow/Kconfig
+++ b/src/mainboard/google/snow/Kconfig
@@ -22,7 +22,7 @@ if BOARD_GOOGLE_SNOW
 config BOARD_SPECIFIC_OPTIONS # dummy
 	def_bool y
 	select ARCH_ARMV7
-	select CPU_SAMSUNG_EXYNOS5
+	select CPU_SAMSUNG_EXYNOS5250
 	select HAVE_UART_MEMORY_MAPPED
 	select EC_GOOGLE_CHROMEEC
 	select EC_GOOGLE_CHROMEEC_I2C



More information about the coreboot-gerrit mailing list