Merge branch 'u-boot-ti/master' into 'u-boot-arm/master'
diff --git a/arch/arm/cpu/armv7/Makefile b/arch/arm/cpu/armv7/Makefile
index 0467d00..119ebb3 100644
--- a/arch/arm/cpu/armv7/Makefile
+++ b/arch/arm/cpu/armv7/Makefile
@@ -23,6 +23,7 @@
 obj-y	+= virt-v7.o
 endif
 
+obj-$(CONFIG_KONA) += kona-common/
 obj-$(CONFIG_OMAP_COMMON) += omap-common/
 obj-$(CONFIG_TEGRA) += tegra-common/
 
diff --git a/arch/arm/cpu/armv7/bcm281xx/Makefile b/arch/arm/cpu/armv7/bcm281xx/Makefile
new file mode 100644
index 0000000..98f5aa5
--- /dev/null
+++ b/arch/arm/cpu/armv7/bcm281xx/Makefile
@@ -0,0 +1,11 @@
+#
+# Copyright 2013 Broadcom Corporation.
+#
+# SPDX-License-Identifier:	GPL-2.0+
+#
+
+obj-y	+= reset.o
+obj-y	+= clk-core.o
+obj-y	+= clk-bcm281xx.o
+obj-y	+= clk-sdio.o
+obj-y	+= clk-bsc.o
diff --git a/arch/arm/cpu/armv7/bcm281xx/clk-bcm281xx.c b/arch/arm/cpu/armv7/bcm281xx/clk-bcm281xx.c
new file mode 100644
index 0000000..bc8a170
--- /dev/null
+++ b/arch/arm/cpu/armv7/bcm281xx/clk-bcm281xx.c
@@ -0,0 +1,523 @@
+/*
+ * Copyright 2013 Broadcom Corporation.
+ *
+ * SPDX-License-Identifier:      GPL-2.0+
+ */
+
+/*
+ *
+ * bcm281xx-specific clock tables
+ *
+ */
+
+#include <common.h>
+#include <asm/io.h>
+#include <asm/errno.h>
+#include <asm/arch/sysmap.h>
+#include <asm/kona-common/clk.h>
+#include "clk-core.h"
+
+#define CLOCK_1K		1000
+#define CLOCK_1M		(CLOCK_1K * 1000)
+
+/* declare a reference clock */
+#define DECLARE_REF_CLK(clk_name, clk_parent, clk_rate, clk_div) \
+static struct refclk clk_name = { \
+	.clk    =       { \
+		.name   =       #clk_name, \
+		.parent =       clk_parent, \
+		.rate   =       clk_rate, \
+		.div    =       clk_div, \
+		.ops    =       &ref_clk_ops, \
+	}, \
+}
+
+/*
+ * Reference clocks
+ */
+
+/* Declare a list of reference clocks */
+DECLARE_REF_CLK(ref_crystal,	0,		26  * CLOCK_1M,	1);
+DECLARE_REF_CLK(var_96m,	0,		96  * CLOCK_1M,	1);
+DECLARE_REF_CLK(ref_96m,	0,		96  * CLOCK_1M,	1);
+DECLARE_REF_CLK(ref_312m,	0,		312 * CLOCK_1M,	0);
+DECLARE_REF_CLK(ref_104m,	&ref_312m.clk,	104 * CLOCK_1M,	3);
+DECLARE_REF_CLK(ref_52m,	&ref_104m.clk,	52  * CLOCK_1M,	2);
+DECLARE_REF_CLK(ref_13m,	&ref_52m.clk,	13  * CLOCK_1M,	4);
+DECLARE_REF_CLK(var_312m,	0,		312 * CLOCK_1M,	0);
+DECLARE_REF_CLK(var_104m,	&var_312m.clk,	104 * CLOCK_1M,	3);
+DECLARE_REF_CLK(var_52m,	&var_104m.clk,	52  * CLOCK_1M,	2);
+DECLARE_REF_CLK(var_13m,	&var_52m.clk,	13  * CLOCK_1M,	4);
+
+struct refclk_lkup {
+	struct refclk *procclk;
+	const char *name;
+};
+
+/* Lookup table for string to clk tranlation */
+#define MKSTR(x) {&x, #x}
+static struct refclk_lkup refclk_str_tbl[] = {
+	MKSTR(ref_crystal), MKSTR(var_96m), MKSTR(ref_96m),
+	MKSTR(ref_312m), MKSTR(ref_104m), MKSTR(ref_52m),
+	MKSTR(ref_13m), MKSTR(var_312m), MKSTR(var_104m),
+	MKSTR(var_52m), MKSTR(var_13m),
+};
+
+int refclk_entries = sizeof(refclk_str_tbl)/sizeof(refclk_str_tbl[0]);
+
+/* convert ref clock string to clock structure pointer */
+struct refclk *refclk_str_to_clk(const char *name)
+{
+	int i;
+	struct refclk_lkup *tblp = refclk_str_tbl;
+	for (i = 0; i < refclk_entries; i++, tblp++) {
+		if (!(strcmp(name, tblp->name)))
+			return tblp->procclk;
+	}
+	return NULL;
+}
+
+/* frequency tables indexed by freq_id */
+unsigned long master_axi_freq_tbl[8] = {
+	26 * CLOCK_1M,
+	52 * CLOCK_1M,
+	104 * CLOCK_1M,
+	156 * CLOCK_1M,
+	156 * CLOCK_1M,
+	208 * CLOCK_1M,
+	312 * CLOCK_1M,
+	312 * CLOCK_1M
+};
+
+unsigned long master_ahb_freq_tbl[8] = {
+	26 * CLOCK_1M,
+	52 * CLOCK_1M,
+	52 * CLOCK_1M,
+	52 * CLOCK_1M,
+	78 * CLOCK_1M,
+	104 * CLOCK_1M,
+	104 * CLOCK_1M,
+	156 * CLOCK_1M
+};
+
+unsigned long slave_axi_freq_tbl[8] = {
+	26 * CLOCK_1M,
+	52 * CLOCK_1M,
+	78 * CLOCK_1M,
+	104 * CLOCK_1M,
+	156 * CLOCK_1M,
+	156 * CLOCK_1M
+};
+
+unsigned long slave_apb_freq_tbl[8] = {
+	26 * CLOCK_1M,
+	26 * CLOCK_1M,
+	39 * CLOCK_1M,
+	52 * CLOCK_1M,
+	52 * CLOCK_1M,
+	78 * CLOCK_1M
+};
+
+static struct bus_clk_data bsc1_apb_data = {
+	.gate = HW_SW_GATE_AUTO(0x0458, 16, 0, 1),
+};
+
+static struct bus_clk_data bsc2_apb_data = {
+	.gate = HW_SW_GATE_AUTO(0x045c, 16, 0, 1),
+};
+
+static struct bus_clk_data bsc3_apb_data = {
+	.gate = HW_SW_GATE_AUTO(0x0484, 16, 0, 1),
+};
+
+/* * Master CCU clocks */
+static struct peri_clk_data sdio1_data = {
+	.gate		= HW_SW_GATE(0x0358, 18, 2, 3),
+	.clocks		= CLOCKS("ref_crystal",
+				 "var_52m",
+				 "ref_52m",
+				 "var_96m",
+				 "ref_96m"),
+	.sel		= SELECTOR(0x0a28, 0, 3),
+	.div		= DIVIDER(0x0a28, 4, 14),
+	.trig		= TRIGGER(0x0afc, 9),
+};
+
+static struct peri_clk_data sdio2_data = {
+	.gate		= HW_SW_GATE(0x035c, 18, 2, 3),
+	.clocks		= CLOCKS("ref_crystal",
+				 "var_52m",
+				 "ref_52m",
+				 "var_96m",
+				 "ref_96m"),
+	.sel		= SELECTOR(0x0a2c, 0, 3),
+	.div		= DIVIDER(0x0a2c, 4, 14),
+	.trig		= TRIGGER(0x0afc, 10),
+};
+
+static struct peri_clk_data sdio3_data = {
+	.gate		= HW_SW_GATE(0x0364, 18, 2, 3),
+	.clocks		= CLOCKS("ref_crystal",
+				 "var_52m",
+				 "ref_52m",
+				 "var_96m",
+				 "ref_96m"),
+	.sel		= SELECTOR(0x0a34, 0, 3),
+	.div		= DIVIDER(0x0a34, 4, 14),
+	.trig		= TRIGGER(0x0afc, 12),
+};
+
+static struct peri_clk_data sdio4_data = {
+	.gate		= HW_SW_GATE(0x0360, 18, 2, 3),
+	.clocks		= CLOCKS("ref_crystal",
+				 "var_52m",
+				 "ref_52m",
+				 "var_96m",
+				 "ref_96m"),
+	.sel		= SELECTOR(0x0a30, 0, 3),
+	.div		= DIVIDER(0x0a30, 4, 14),
+	.trig		= TRIGGER(0x0afc, 11),
+};
+
+static struct peri_clk_data sdio1_sleep_data = {
+	.clocks		= CLOCKS("ref_32k"),
+	.gate		= SW_ONLY_GATE(0x0358, 20, 4),
+};
+
+static struct peri_clk_data sdio2_sleep_data = {
+	.clocks		= CLOCKS("ref_32k"),
+	.gate		= SW_ONLY_GATE(0x035c, 20, 4),
+};
+
+static struct peri_clk_data sdio3_sleep_data = {
+	.clocks		= CLOCKS("ref_32k"),
+	.gate		= SW_ONLY_GATE(0x0364, 20, 4),
+};
+
+static struct peri_clk_data sdio4_sleep_data = {
+	.clocks		= CLOCKS("ref_32k"),
+	.gate		= SW_ONLY_GATE(0x0360, 20, 4),
+};
+
+static struct bus_clk_data sdio1_ahb_data = {
+	.gate		= HW_SW_GATE_AUTO(0x0358, 16, 0, 1),
+};
+
+static struct bus_clk_data sdio2_ahb_data = {
+	.gate		= HW_SW_GATE_AUTO(0x035c, 16, 0, 1),
+};
+
+static struct bus_clk_data sdio3_ahb_data = {
+	.gate		= HW_SW_GATE_AUTO(0x0364, 16, 0, 1),
+};
+
+static struct bus_clk_data sdio4_ahb_data = {
+	.gate		= HW_SW_GATE_AUTO(0x0360, 16, 0, 1),
+};
+
+/* * Slave CCU clocks */
+static struct peri_clk_data bsc1_data = {
+	.gate		= HW_SW_GATE(0x0458, 18, 2, 3),
+	.clocks		= CLOCKS("ref_crystal",
+				 "var_104m",
+				 "ref_104m",
+				 "var_13m",
+				 "ref_13m"),
+	.sel		= SELECTOR(0x0a64, 0, 3),
+	.trig		= TRIGGER(0x0afc, 23),
+};
+
+static struct peri_clk_data bsc2_data = {
+	.gate		= HW_SW_GATE(0x045c, 18, 2, 3),
+	.clocks		= CLOCKS("ref_crystal",
+				 "var_104m",
+				 "ref_104m",
+				 "var_13m",
+				 "ref_13m"),
+	.sel		= SELECTOR(0x0a68, 0, 3),
+	.trig		= TRIGGER(0x0afc, 24),
+};
+
+static struct peri_clk_data bsc3_data = {
+	.gate		= HW_SW_GATE(0x0484, 18, 2, 3),
+	.clocks		= CLOCKS("ref_crystal",
+				 "var_104m",
+				 "ref_104m",
+				 "var_13m",
+				 "ref_13m"),
+	.sel		= SELECTOR(0x0a84, 0, 3),
+	.trig		= TRIGGER(0x0b00, 2),
+};
+
+/*
+ * CCU clocks
+ */
+
+static struct ccu_clock kpm_ccu_clk = {
+	.clk = {
+		.name = "kpm_ccu_clk",
+		.ops = &ccu_clk_ops,
+		.ccu_clk_mgr_base = KONA_MST_CLK_BASE_ADDR,
+	},
+	.num_policy_masks = 1,
+	.policy_freq_offset = 0x00000008,
+	.freq_bit_shift = 8,
+	.policy_ctl_offset = 0x0000000c,
+	.policy0_mask_offset = 0x00000010,
+	.policy1_mask_offset = 0x00000014,
+	.policy2_mask_offset = 0x00000018,
+	.policy3_mask_offset = 0x0000001c,
+	.lvm_en_offset = 0x00000034,
+	.freq_id = 2,
+	.freq_tbl = master_axi_freq_tbl,
+};
+
+static struct ccu_clock kps_ccu_clk = {
+	.clk = {
+		.name = "kps_ccu_clk",
+		.ops = &ccu_clk_ops,
+		.ccu_clk_mgr_base = KONA_SLV_CLK_BASE_ADDR,
+	},
+	.num_policy_masks = 2,
+	.policy_freq_offset = 0x00000008,
+	.freq_bit_shift = 8,
+	.policy_ctl_offset = 0x0000000c,
+	.policy0_mask_offset = 0x00000010,
+	.policy1_mask_offset = 0x00000014,
+	.policy2_mask_offset = 0x00000018,
+	.policy3_mask_offset = 0x0000001c,
+	.policy0_mask2_offset = 0x00000048,
+	.policy1_mask2_offset = 0x0000004c,
+	.policy2_mask2_offset = 0x00000050,
+	.policy3_mask2_offset = 0x00000054,
+	.lvm_en_offset = 0x00000034,
+	.freq_id = 2,
+	.freq_tbl = slave_axi_freq_tbl,
+};
+
+/*
+ * Bus clocks
+ */
+
+/* KPM bus clocks */
+static struct bus_clock sdio1_ahb_clk = {
+	.clk = {
+		.name = "sdio1_ahb_clk",
+		.parent = &kpm_ccu_clk.clk,
+		.ops = &bus_clk_ops,
+		.ccu_clk_mgr_base = KONA_MST_CLK_BASE_ADDR,
+	},
+	.freq_tbl = master_ahb_freq_tbl,
+	.data = &sdio1_ahb_data,
+};
+
+static struct bus_clock sdio2_ahb_clk = {
+	.clk = {
+		.name = "sdio2_ahb_clk",
+		.parent = &kpm_ccu_clk.clk,
+		.ops = &bus_clk_ops,
+		.ccu_clk_mgr_base = KONA_MST_CLK_BASE_ADDR,
+	},
+	.freq_tbl = master_ahb_freq_tbl,
+	.data = &sdio2_ahb_data,
+};
+
+static struct bus_clock sdio3_ahb_clk = {
+	.clk = {
+		.name = "sdio3_ahb_clk",
+		.parent = &kpm_ccu_clk.clk,
+		.ops = &bus_clk_ops,
+		.ccu_clk_mgr_base = KONA_MST_CLK_BASE_ADDR,
+	},
+	.freq_tbl = master_ahb_freq_tbl,
+	.data = &sdio3_ahb_data,
+};
+
+static struct bus_clock sdio4_ahb_clk = {
+	.clk = {
+		.name = "sdio4_ahb_clk",
+		.parent = &kpm_ccu_clk.clk,
+		.ops = &bus_clk_ops,
+		.ccu_clk_mgr_base = KONA_MST_CLK_BASE_ADDR,
+	},
+	.freq_tbl = master_ahb_freq_tbl,
+	.data = &sdio4_ahb_data,
+};
+
+static struct bus_clock bsc1_apb_clk = {
+	.clk = {
+		.name = "bsc1_apb_clk",
+		.parent = &kps_ccu_clk.clk,
+		.ops = &bus_clk_ops,
+		.ccu_clk_mgr_base = KONA_SLV_CLK_BASE_ADDR,
+	},
+	.freq_tbl = slave_apb_freq_tbl,
+	.data = &bsc1_apb_data,
+};
+
+static struct bus_clock bsc2_apb_clk = {
+	.clk = {
+		.name = "bsc2_apb_clk",
+		.parent = &kps_ccu_clk.clk,
+		.ops = &bus_clk_ops,
+		.ccu_clk_mgr_base = KONA_SLV_CLK_BASE_ADDR,
+		},
+	.freq_tbl = slave_apb_freq_tbl,
+	.data = &bsc2_apb_data,
+};
+
+static struct bus_clock bsc3_apb_clk = {
+	.clk = {
+		.name = "bsc3_apb_clk",
+		.parent = &kps_ccu_clk.clk,
+		.ops = &bus_clk_ops,
+		.ccu_clk_mgr_base = KONA_SLV_CLK_BASE_ADDR,
+		},
+	.freq_tbl = slave_apb_freq_tbl,
+	.data = &bsc3_apb_data,
+};
+
+/* KPM peripheral */
+static struct peri_clock sdio1_clk = {
+	.clk = {
+		.name = "sdio1_clk",
+		.parent = &ref_52m.clk,
+		.ops = &peri_clk_ops,
+		.ccu_clk_mgr_base = KONA_MST_CLK_BASE_ADDR,
+	},
+	.data = &sdio1_data,
+};
+
+static struct peri_clock sdio2_clk = {
+	.clk = {
+		.name = "sdio2_clk",
+		.parent = &ref_52m.clk,
+		.ops = &peri_clk_ops,
+		.ccu_clk_mgr_base = KONA_MST_CLK_BASE_ADDR,
+	},
+	.data = &sdio2_data,
+};
+
+static struct peri_clock sdio3_clk = {
+	.clk = {
+		.name = "sdio3_clk",
+		.parent = &ref_52m.clk,
+		.ops = &peri_clk_ops,
+		.ccu_clk_mgr_base = KONA_MST_CLK_BASE_ADDR,
+	},
+	.data = &sdio3_data,
+};
+
+static struct peri_clock sdio4_clk = {
+	.clk = {
+		.name = "sdio4_clk",
+		.parent = &ref_52m.clk,
+		.ops = &peri_clk_ops,
+		.ccu_clk_mgr_base = KONA_MST_CLK_BASE_ADDR,
+	},
+	.data = &sdio4_data,
+};
+
+static struct peri_clock sdio1_sleep_clk = {
+	.clk = {
+		.name = "sdio1_sleep_clk",
+		.parent = &kpm_ccu_clk.clk,
+		.ops = &bus_clk_ops,
+		.ccu_clk_mgr_base = KONA_MST_CLK_BASE_ADDR,
+	},
+	.data = &sdio1_sleep_data,
+};
+
+static struct peri_clock sdio2_sleep_clk = {
+	.clk = {
+		.name = "sdio2_sleep_clk",
+		.parent = &kpm_ccu_clk.clk,
+		.ops = &bus_clk_ops,
+		.ccu_clk_mgr_base = KONA_MST_CLK_BASE_ADDR,
+	},
+	.data = &sdio2_sleep_data,
+};
+
+static struct peri_clock sdio3_sleep_clk = {
+	.clk = {
+		.name = "sdio3_sleep_clk",
+		.parent = &kpm_ccu_clk.clk,
+		.ops = &bus_clk_ops,
+		.ccu_clk_mgr_base = KONA_MST_CLK_BASE_ADDR,
+	},
+	.data = &sdio3_sleep_data,
+};
+
+static struct peri_clock sdio4_sleep_clk = {
+	.clk = {
+		.name = "sdio4_sleep_clk",
+		.parent = &kpm_ccu_clk.clk,
+		.ops = &bus_clk_ops,
+		.ccu_clk_mgr_base = KONA_MST_CLK_BASE_ADDR,
+	},
+	.data = &sdio4_sleep_data,
+};
+
+/* KPS peripheral clock */
+static struct peri_clock bsc1_clk = {
+	.clk = {
+		.name = "bsc1_clk",
+		.parent = &ref_13m.clk,
+		.rate = 13 * CLOCK_1M,
+		.div = 1,
+		.ops = &peri_clk_ops,
+		.ccu_clk_mgr_base = KONA_SLV_CLK_BASE_ADDR,
+	},
+	.data = &bsc1_data,
+};
+
+static struct peri_clock bsc2_clk = {
+	.clk = {
+		.name = "bsc2_clk",
+		.parent = &ref_13m.clk,
+		.rate = 13 * CLOCK_1M,
+		.div = 1,
+		.ops = &peri_clk_ops,
+		.ccu_clk_mgr_base = KONA_SLV_CLK_BASE_ADDR,
+	},
+	.data = &bsc2_data,
+};
+
+static struct peri_clock bsc3_clk = {
+	.clk = {
+		.name = "bsc3_clk",
+		.parent = &ref_13m.clk,
+		.rate = 13 * CLOCK_1M,
+		.div = 1,
+		.ops = &peri_clk_ops,
+		.ccu_clk_mgr_base = KONA_SLV_CLK_BASE_ADDR,
+	},
+	.data = &bsc3_data,
+};
+
+/* public table for registering clocks */
+struct clk_lookup arch_clk_tbl[] = {
+	/* Peripheral clocks */
+	CLK_LK(sdio1),
+	CLK_LK(sdio2),
+	CLK_LK(sdio3),
+	CLK_LK(sdio4),
+	CLK_LK(sdio1_sleep),
+	CLK_LK(sdio2_sleep),
+	CLK_LK(sdio3_sleep),
+	CLK_LK(sdio4_sleep),
+	CLK_LK(bsc1),
+	CLK_LK(bsc2),
+	CLK_LK(bsc3),
+	/* Bus clocks */
+	CLK_LK(sdio1_ahb),
+	CLK_LK(sdio2_ahb),
+	CLK_LK(sdio3_ahb),
+	CLK_LK(sdio4_ahb),
+	CLK_LK(bsc1_apb),
+	CLK_LK(bsc2_apb),
+	CLK_LK(bsc3_apb),
+};
+
+/* public array size */
+unsigned int arch_clk_tbl_array_size = ARRAY_SIZE(arch_clk_tbl);
diff --git a/arch/arm/cpu/armv7/bcm281xx/clk-bsc.c b/arch/arm/cpu/armv7/bcm281xx/clk-bsc.c
new file mode 100644
index 0000000..ba55d0a
--- /dev/null
+++ b/arch/arm/cpu/armv7/bcm281xx/clk-bsc.c
@@ -0,0 +1,52 @@
+/*
+ * Copyright 2013 Broadcom Corporation.
+ *
+ * SPDX-License-Identifier:      GPL-2.0+
+ */
+
+#include <common.h>
+#include <asm/io.h>
+#include <asm/errno.h>
+#include <asm/arch/sysmap.h>
+#include <asm/kona-common/clk.h>
+#include "clk-core.h"
+
+/* Enable appropriate clocks for a BSC/I2C port */
+int clk_bsc_enable(void *base)
+{
+	int ret;
+	char *bscstr, *apbstr;
+
+	switch ((u32) base) {
+	case PMU_BSC_BASE_ADDR:
+		/* PMU clock is always enabled */
+		return 0;
+	case BSC1_BASE_ADDR:
+		bscstr = "bsc1_clk";
+		apbstr = "bsc1_apb_clk";
+		break;
+	case BSC2_BASE_ADDR:
+		bscstr = "bsc2_clk";
+		apbstr = "bsc2_apb_clk";
+		break;
+	case BSC3_BASE_ADDR:
+		bscstr = "bsc3_clk";
+		apbstr = "bsc3_apb_clk";
+		break;
+	default:
+		printf("%s: base 0x%p not found\n", __func__, base);
+		return -EINVAL;
+	}
+
+	/* Note that the bus clock must be enabled first */
+
+	ret = clk_get_and_enable(apbstr);
+	if (ret)
+		return ret;
+
+	ret = clk_get_and_enable(bscstr);
+	if (ret)
+		return ret;
+
+	return 0;
+}
diff --git a/arch/arm/cpu/armv7/bcm281xx/clk-core.c b/arch/arm/cpu/armv7/bcm281xx/clk-core.c
new file mode 100644
index 0000000..d442583
--- /dev/null
+++ b/arch/arm/cpu/armv7/bcm281xx/clk-core.c
@@ -0,0 +1,513 @@
+/*
+ * Copyright 2013 Broadcom Corporation.
+ *
+ * SPDX-License-Identifier:      GPL-2.0+
+ */
+
+/*
+ *
+ * bcm281xx architecture clock framework
+ *
+ */
+
+#include <common.h>
+#include <asm/io.h>
+#include <asm/errno.h>
+#include <bitfield.h>
+#include <asm/arch/sysmap.h>
+#include <asm/kona-common/clk.h>
+#include "clk-core.h"
+
+#define CLK_WR_ACCESS_PASSWORD	0x00a5a501
+#define WR_ACCESS_OFFSET	0	/* common to all clock blocks */
+#define POLICY_CTL_GO		1	/* Load and refresh policy masks */
+#define POLICY_CTL_GO_ATL	4	/* Active Load */
+
+/* Helper function */
+int clk_get_and_enable(char *clkstr)
+{
+	int ret = 0;
+	struct clk *c;
+
+	debug("%s: %s\n", __func__, clkstr);
+
+	c = clk_get(clkstr);
+	if (c) {
+		ret = clk_enable(c);
+		if (ret)
+			return ret;
+	} else {
+		printf("%s: Couldn't find %s\n", __func__, clkstr);
+		return -EINVAL;
+	}
+	return ret;
+}
+
+/*
+ * Poll a register in a CCU's address space, returning when the
+ * specified bit in that register's value is set (or clear).  Delay
+ * a microsecond after each read of the register.  Returns true if
+ * successful, or false if we gave up trying.
+ *
+ * Caller must ensure the CCU lock is held.
+ */
+#define CLK_GATE_DELAY_USEC 2000
+static inline int wait_bit(void *base, u32 offset, u32 bit, bool want)
+{
+	unsigned int tries;
+	u32 bit_mask = 1 << bit;
+
+	for (tries = 0; tries < CLK_GATE_DELAY_USEC; tries++) {
+		u32 val;
+		bool bit_val;
+
+		val = readl(base + offset);
+		bit_val = (val & bit_mask) ? 1 : 0;
+		if (bit_val == want)
+			return 0;	/* success */
+		udelay(1);
+	}
+
+	debug("%s: timeout on addr 0x%p, waiting for bit %d to go to %d\n",
+	      __func__, base + offset, bit, want);
+
+	return -ETIMEDOUT;
+}
+
+/* Enable a peripheral clock */
+static int peri_clk_enable(struct clk *c, int enable)
+{
+	int ret = 0;
+	u32 reg;
+	struct peri_clock *peri_clk = to_peri_clk(c);
+	struct peri_clk_data *cd = peri_clk->data;
+	struct bcm_clk_gate *gate = &cd->gate;
+	void *base = (void *)c->ccu_clk_mgr_base;
+
+
+	debug("%s: %s\n", __func__, c->name);
+
+	clk_get_rate(c);	/* Make sure rate and sel are filled in */
+
+	/* enable access */
+	writel(CLK_WR_ACCESS_PASSWORD, base + WR_ACCESS_OFFSET);
+
+	if (enable) {
+		debug("%s %s set rate %lu div %lu sel %d parent %lu\n",
+		      __func__, c->name, c->rate, c->div, c->sel,
+		      c->parent->rate);
+
+		/*
+		 * clkgate - only software controllable gates are
+		 * supported by u-boot which includes all clocks
+		 * that matter. This avoids bringing in a lot of extra
+		 * complexity as done in the kernel framework.
+		 */
+		if (gate_exists(gate)) {
+			reg = readl(base + cd->gate.offset);
+			reg |= (1 << cd->gate.en_bit);
+			writel(reg, base + cd->gate.offset);
+		}
+
+		/* div and pll select */
+		if (divider_exists(&cd->div)) {
+			reg = readl(base + cd->div.offset);
+			bitfield_replace(reg, cd->div.shift, cd->div.width,
+					 c->div - 1);
+			writel(reg, base + cd->div.offset);
+		}
+
+		/* frequency selector */
+		if (selector_exists(&cd->sel)) {
+			reg = readl(base + cd->sel.offset);
+			bitfield_replace(reg, cd->sel.shift, cd->sel.width,
+					 c->sel);
+			writel(reg, base + cd->sel.offset);
+		}
+
+		/* trigger */
+		if (trigger_exists(&cd->trig)) {
+			writel((1 << cd->trig.bit), base + cd->trig.offset);
+
+			/* wait for trigger status bit to go to 0 */
+			ret = wait_bit(base, cd->trig.offset, cd->trig.bit, 0);
+			if (ret)
+				return ret;
+		}
+
+		/* wait for running (status_bit = 1) */
+		ret = wait_bit(base, cd->gate.offset, cd->gate.status_bit, 1);
+		if (ret)
+			return ret;
+	} else {
+		debug("%s disable clock %s\n", __func__, c->name);
+
+		/* clkgate */
+		reg = readl(base + cd->gate.offset);
+		reg &= ~(1 << cd->gate.en_bit);
+		writel(reg, base + cd->gate.offset);
+
+		/* wait for stop (status_bit = 0) */
+		ret = wait_bit(base, cd->gate.offset, cd->gate.status_bit, 0);
+	}
+
+	/* disable access */
+	writel(0, base + WR_ACCESS_OFFSET);
+
+	return ret;
+}
+
+/* Set the rate of a peripheral clock */
+static int peri_clk_set_rate(struct clk *c, unsigned long rate)
+{
+	int ret = 0;
+	int i;
+	unsigned long diff;
+	unsigned long new_rate = 0, div = 1;
+	struct peri_clock *peri_clk = to_peri_clk(c);
+	struct peri_clk_data *cd = peri_clk->data;
+	const char **clock;
+
+	debug("%s: %s\n", __func__, c->name);
+	diff = rate;
+
+	i = 0;
+	for (clock = cd->clocks; *clock; clock++, i++) {
+		struct refclk *ref = refclk_str_to_clk(*clock);
+		if (!ref) {
+			printf("%s: Lookup of %s failed\n", __func__, *clock);
+			return -EINVAL;
+		}
+
+		/* round to the new rate */
+		div = ref->clk.rate / rate;
+		if (div == 0)
+			div = 1;
+
+		new_rate = ref->clk.rate / div;
+
+		/* get the min diff */
+		if (abs(new_rate - rate) < diff) {
+			diff = abs(new_rate - rate);
+			c->sel = i;
+			c->parent = &ref->clk;
+			c->rate = new_rate;
+			c->div = div;
+		}
+	}
+
+	debug("%s %s set rate %lu div %lu sel %d parent %lu\n", __func__,
+	      c->name, c->rate, c->div, c->sel, c->parent->rate);
+	return ret;
+}
+
+/* Get the rate of a peripheral clock */
+static unsigned long peri_clk_get_rate(struct clk *c)
+{
+	struct peri_clock *peri_clk = to_peri_clk(c);
+	struct peri_clk_data *cd = peri_clk->data;
+	void *base = (void *)c->ccu_clk_mgr_base;
+	int div = 1;
+	const char **clock;
+	struct refclk *ref;
+	u32 reg;
+
+	debug("%s: %s\n", __func__, c->name);
+	if (selector_exists(&cd->sel)) {
+		reg = readl(base + cd->sel.offset);
+		c->sel = bitfield_extract(reg, cd->sel.shift, cd->sel.width);
+	} else {
+		/*
+		 * For peri clocks that don't have a selector, the single
+		 * reference clock will always exist at index 0.
+		 */
+		c->sel = 0;
+	}
+
+	if (divider_exists(&cd->div)) {
+		reg = readl(base + cd->div.offset);
+		div = bitfield_extract(reg, cd->div.shift, cd->div.width);
+		div += 1;
+	}
+
+	clock = cd->clocks;
+	ref = refclk_str_to_clk(clock[c->sel]);
+	if (!ref) {
+		printf("%s: Can't lookup %s\n", __func__, clock[c->sel]);
+		return 0;
+	}
+
+	c->parent = &ref->clk;
+	c->div = div;
+	c->rate = c->parent->rate / c->div;
+	debug("%s parent rate %lu div %d sel %d rate %lu\n", __func__,
+	      c->parent->rate, div, c->sel, c->rate);
+
+	return c->rate;
+}
+
+/* Peripheral clock operations */
+struct clk_ops peri_clk_ops = {
+	.enable = peri_clk_enable,
+	.set_rate = peri_clk_set_rate,
+	.get_rate = peri_clk_get_rate,
+};
+
+/* Enable a CCU clock */
+static int ccu_clk_enable(struct clk *c, int enable)
+{
+	struct ccu_clock *ccu_clk = to_ccu_clk(c);
+	void *base = (void *)c->ccu_clk_mgr_base;
+	int ret = 0;
+	u32 reg;
+
+	debug("%s: %s\n", __func__, c->name);
+	if (!enable)
+		return -EINVAL;	/* CCU clock cannot shutdown */
+
+	/* enable access */
+	writel(CLK_WR_ACCESS_PASSWORD, base + WR_ACCESS_OFFSET);
+
+	/* config enable for policy engine */
+	writel(1, base + ccu_clk->lvm_en_offset);
+
+	/* wait for bit to go to 0 */
+	ret = wait_bit(base, ccu_clk->lvm_en_offset, 0, 0);
+	if (ret)
+		return ret;
+
+	/* freq ID */
+	if (!ccu_clk->freq_bit_shift)
+		ccu_clk->freq_bit_shift = 8;
+
+	/* Set frequency id for each of the 4 policies */
+	reg = ccu_clk->freq_id |
+	    (ccu_clk->freq_id << (ccu_clk->freq_bit_shift)) |
+	    (ccu_clk->freq_id << (ccu_clk->freq_bit_shift * 2)) |
+	    (ccu_clk->freq_id << (ccu_clk->freq_bit_shift * 3));
+	writel(reg, base + ccu_clk->policy_freq_offset);
+
+	/* enable all clock mask */
+	writel(0x7fffffff, base + ccu_clk->policy0_mask_offset);
+	writel(0x7fffffff, base + ccu_clk->policy1_mask_offset);
+	writel(0x7fffffff, base + ccu_clk->policy2_mask_offset);
+	writel(0x7fffffff, base + ccu_clk->policy3_mask_offset);
+
+	if (ccu_clk->num_policy_masks == 2) {
+		writel(0x7fffffff, base + ccu_clk->policy0_mask2_offset);
+		writel(0x7fffffff, base + ccu_clk->policy1_mask2_offset);
+		writel(0x7fffffff, base + ccu_clk->policy2_mask2_offset);
+		writel(0x7fffffff, base + ccu_clk->policy3_mask2_offset);
+	}
+
+	/* start policy engine */
+	reg = readl(base + ccu_clk->policy_ctl_offset);
+	reg |= (POLICY_CTL_GO + POLICY_CTL_GO_ATL);
+	writel(reg, base + ccu_clk->policy_ctl_offset);
+
+	/* wait till started */
+	ret = wait_bit(base, ccu_clk->policy_ctl_offset, 0, 0);
+	if (ret)
+		return ret;
+
+	/* disable access */
+	writel(0, base + WR_ACCESS_OFFSET);
+
+	return ret;
+}
+
+/* Get the CCU clock rate */
+static unsigned long ccu_clk_get_rate(struct clk *c)
+{
+	struct ccu_clock *ccu_clk = to_ccu_clk(c);
+	debug("%s: %s\n", __func__, c->name);
+	c->rate = ccu_clk->freq_tbl[ccu_clk->freq_id];
+	return c->rate;
+}
+
+/* CCU clock operations */
+struct clk_ops ccu_clk_ops = {
+	.enable = ccu_clk_enable,
+	.get_rate = ccu_clk_get_rate,
+};
+
+/* Enable a bus clock */
+static int bus_clk_enable(struct clk *c, int enable)
+{
+	struct bus_clock *bus_clk = to_bus_clk(c);
+	struct bus_clk_data *cd = bus_clk->data;
+	void *base = (void *)c->ccu_clk_mgr_base;
+	int ret = 0;
+	u32 reg;
+
+	debug("%s: %s\n", __func__, c->name);
+	/* enable access */
+	writel(CLK_WR_ACCESS_PASSWORD, base + WR_ACCESS_OFFSET);
+
+	/* enable gating */
+	reg = readl(base + cd->gate.offset);
+	if (!!(reg & (1 << cd->gate.status_bit)) == !!enable)
+		debug("%s already %s\n", c->name,
+		      enable ? "enabled" : "disabled");
+	else {
+		int want = (enable) ? 1 : 0;
+		reg |= (1 << cd->gate.hw_sw_sel_bit);
+
+		if (enable)
+			reg |= (1 << cd->gate.en_bit);
+		else
+			reg &= ~(1 << cd->gate.en_bit);
+
+		writel(reg, base + cd->gate.offset);
+		ret = wait_bit(base, cd->gate.offset, cd->gate.status_bit,
+			       want);
+		if (ret)
+			return ret;
+	}
+
+	/* disable access */
+	writel(0, base + WR_ACCESS_OFFSET);
+
+	return ret;
+}
+
+/* Get the rate of a bus clock */
+static unsigned long bus_clk_get_rate(struct clk *c)
+{
+	struct bus_clock *bus_clk = to_bus_clk(c);
+	struct ccu_clock *ccu_clk;
+
+	debug("%s: %s\n", __func__, c->name);
+	ccu_clk = to_ccu_clk(c->parent);
+
+	c->rate = bus_clk->freq_tbl[ccu_clk->freq_id];
+	c->div = ccu_clk->freq_tbl[ccu_clk->freq_id] / c->rate;
+	return c->rate;
+}
+
+/* Bus clock operations */
+struct clk_ops bus_clk_ops = {
+	.enable = bus_clk_enable,
+	.get_rate = bus_clk_get_rate,
+};
+
+/* Enable a reference clock */
+static int ref_clk_enable(struct clk *c, int enable)
+{
+	debug("%s: %s\n", __func__, c->name);
+	return 0;
+}
+
+/* Reference clock operations */
+struct clk_ops ref_clk_ops = {
+	.enable = ref_clk_enable,
+};
+
+/*
+ * clk.h implementation follows
+ */
+
+/* Initialize the clock framework */
+int clk_init(void)
+{
+	debug("%s:\n", __func__);
+	return 0;
+}
+
+/* Get a clock handle, give a name string */
+struct clk *clk_get(const char *con_id)
+{
+	int i;
+	struct clk_lookup *clk_tblp;
+
+	debug("%s: %s\n", __func__, con_id);
+
+	clk_tblp = arch_clk_tbl;
+	for (i = 0; i < arch_clk_tbl_array_size; i++, clk_tblp++) {
+		if (clk_tblp->con_id) {
+			if (!con_id || strcmp(clk_tblp->con_id, con_id))
+				continue;
+			return clk_tblp->clk;
+		}
+	}
+	return NULL;
+}
+
+/* Enable a clock */
+int clk_enable(struct clk *c)
+{
+	int ret = 0;
+
+	debug("%s: %s\n", __func__, c->name);
+	if (!c->ops || !c->ops->enable)
+		return -1;
+
+	/* enable parent clock first */
+	if (c->parent)
+		ret = clk_enable(c->parent);
+
+	if (ret)
+		return ret;
+
+	if (!c->use_cnt) {
+		c->use_cnt++;
+		ret = c->ops->enable(c, 1);
+	}
+
+	return ret;
+}
+
+/* Disable a clock */
+void clk_disable(struct clk *c)
+{
+	debug("%s: %s\n", __func__, c->name);
+	if (!c->ops || !c->ops->enable)
+		return;
+
+	if (c->use_cnt) {
+		c->use_cnt--;
+		c->ops->enable(c, 0);
+	}
+
+	/* disable parent */
+	if (c->parent)
+		clk_disable(c->parent);
+}
+
+/* Get the clock rate */
+unsigned long clk_get_rate(struct clk *c)
+{
+	unsigned long rate;
+
+	debug("%s: %s\n", __func__, c->name);
+	if (!c || !c->ops || !c->ops->get_rate)
+		return 0;
+
+	rate = c->ops->get_rate(c);
+	debug("%s: rate = %ld\n", __func__, rate);
+	return rate;
+}
+
+/* Set the clock rate */
+int clk_set_rate(struct clk *c, unsigned long rate)
+{
+	int ret;
+
+	debug("%s: %s rate=%ld\n", __func__, c->name, rate);
+	if (!c || !c->ops || !c->ops->set_rate)
+		return -EINVAL;
+
+	if (c->use_cnt)
+		return -EINVAL;
+
+	ret = c->ops->set_rate(c, rate);
+
+	return ret;
+}
+
+/* Not required for this arch */
+/*
+long clk_round_rate(struct clk *clk, unsigned long rate);
+int clk_set_parent(struct clk *clk, struct clk *parent);
+struct clk *clk_get_parent(struct clk *clk);
+*/
diff --git a/arch/arm/cpu/armv7/bcm281xx/clk-core.h b/arch/arm/cpu/armv7/bcm281xx/clk-core.h
new file mode 100644
index 0000000..882a297
--- /dev/null
+++ b/arch/arm/cpu/armv7/bcm281xx/clk-core.h
@@ -0,0 +1,495 @@
+/*
+ * Copyright 2013 Broadcom Corporation.
+ *
+ * SPDX-License-Identifier:      GPL-2.0+
+ */
+
+#include <linux/stddef.h>
+
+#ifdef CONFIG_CLK_DEBUG
+#undef writel
+#undef readl
+static inline void writel(u32 val, void *addr)
+{
+	printf("Write [0x%p] = 0x%08x\n", addr, val);
+	*(u32 *)addr = val;
+}
+
+static inline u32 readl(void *addr)
+{
+	u32 val = *(u32 *)addr;
+	printf("Read  [0x%p] = 0x%08x\n", addr, val);
+	return val;
+}
+#endif
+
+struct clk;
+
+struct clk_lookup {
+	const char *dev_id;
+	const char *con_id;
+	struct clk *clk;
+};
+
+extern struct clk_lookup arch_clk_tbl[];
+extern unsigned int arch_clk_tbl_array_size;
+
+/**
+ * struct clk_ops - standard clock operations
+ * @enable: enable/disable clock, see clk_enable() and clk_disable()
+ * @set_rate: set the clock rate, see clk_set_rate().
+ * @get_rate: get the clock rate, see clk_get_rate().
+ * @round_rate: round a given clock rate, see clk_round_rate().
+ * @set_parent: set the clock's parent, see clk_set_parent().
+ *
+ * Group the common clock implementations together so that we
+ * don't have to keep setting the same fiels again. We leave
+ * enable in struct clk.
+ *
+ */
+struct clk_ops {
+	int (*enable) (struct clk *c, int enable);
+	int (*set_rate) (struct clk *c, unsigned long rate);
+	unsigned long (*get_rate) (struct clk *c);
+	unsigned long (*round_rate) (struct clk *c, unsigned long rate);
+	int (*set_parent) (struct clk *c, struct clk *parent);
+};
+
+struct clk {
+	struct clk *parent;
+	const char *name;
+	int use_cnt;
+	unsigned long rate;	/* in HZ */
+
+	/* programmable divider. 0 means fixed ratio to parent clock */
+	unsigned long div;
+
+	struct clk_src *src;
+	struct clk_ops *ops;
+
+	unsigned long ccu_clk_mgr_base;
+	int sel;
+};
+
+struct refclk *refclk_str_to_clk(const char *name);
+
+#define U8_MAX	((u8)~0U)
+#define U32_MAX	((u32)~0U)
+#define U64_MAX	((u64)~0U)
+
+/* The common clock framework uses u8 to represent a parent index */
+#define PARENT_COUNT_MAX	((u32)U8_MAX)
+
+#define BAD_CLK_INDEX		U8_MAX	/* Can't ever be valid */
+#define BAD_CLK_NAME		((const char *)-1)
+
+#define BAD_SCALED_DIV_VALUE	U64_MAX
+
+/*
+ * Utility macros for object flag management.  If possible, flags
+ * should be defined such that 0 is the desired default value.
+ */
+#define FLAG(type, flag)		BCM_CLK_ ## type ## _FLAGS_ ## flag
+#define FLAG_SET(obj, type, flag)	((obj)->flags |= FLAG(type, flag))
+#define FLAG_CLEAR(obj, type, flag)	((obj)->flags &= ~(FLAG(type, flag)))
+#define FLAG_FLIP(obj, type, flag)	((obj)->flags ^= FLAG(type, flag))
+#define FLAG_TEST(obj, type, flag)	(!!((obj)->flags & FLAG(type, flag)))
+
+/* Clock field state tests */
+
+#define gate_exists(gate)		FLAG_TEST(gate, GATE, EXISTS)
+#define gate_is_enabled(gate)		FLAG_TEST(gate, GATE, ENABLED)
+#define gate_is_hw_controllable(gate)	FLAG_TEST(gate, GATE, HW)
+#define gate_is_sw_controllable(gate)	FLAG_TEST(gate, GATE, SW)
+#define gate_is_sw_managed(gate)	FLAG_TEST(gate, GATE, SW_MANAGED)
+#define gate_is_no_disable(gate)	FLAG_TEST(gate, GATE, NO_DISABLE)
+
+#define gate_flip_enabled(gate)		FLAG_FLIP(gate, GATE, ENABLED)
+
+#define divider_exists(div)		FLAG_TEST(div, DIV, EXISTS)
+#define divider_is_fixed(div)		FLAG_TEST(div, DIV, FIXED)
+#define divider_has_fraction(div)	(!divider_is_fixed(div) && \
+						(div)->frac_width > 0)
+
+#define selector_exists(sel)		((sel)->width != 0)
+#define trigger_exists(trig)		FLAG_TEST(trig, TRIG, EXISTS)
+
+/* Clock type, used to tell common block what it's part of */
+enum bcm_clk_type {
+	bcm_clk_none,		/* undefined clock type */
+	bcm_clk_bus,
+	bcm_clk_core,
+	bcm_clk_peri
+};
+
+/*
+ * Gating control and status is managed by a 32-bit gate register.
+ *
+ * There are several types of gating available:
+ * - (no gate)
+ *     A clock with no gate is assumed to be always enabled.
+ * - hardware-only gating (auto-gating)
+ *     Enabling or disabling clocks with this type of gate is
+ *     managed automatically by the hardware.  Such clocks can be
+ *     considered by the software to be enabled.  The current status
+ *     of auto-gated clocks can be read from the gate status bit.
+ * - software-only gating
+ *     Auto-gating is not available for this type of clock.
+ *     Instead, software manages whether it's enabled by setting or
+ *     clearing the enable bit.  The current gate status of a gate
+ *     under software control can be read from the gate status bit.
+ *     To ensure a change to the gating status is complete, the
+ *     status bit can be polled to verify that the gate has entered
+ *     the desired state.
+ * - selectable hardware or software gating
+ *     Gating for this type of clock can be configured to be either
+ *     under software or hardware control.  Which type is in use is
+ *     determined by the hw_sw_sel bit of the gate register.
+ */
+struct bcm_clk_gate {
+	u32 offset;		/* gate register offset */
+	u32 status_bit;		/* 0: gate is disabled; 0: gatge is enabled */
+	u32 en_bit;		/* 0: disable; 1: enable */
+	u32 hw_sw_sel_bit;	/* 0: hardware gating; 1: software gating */
+	u32 flags;		/* BCM_CLK_GATE_FLAGS_* below */
+};
+
+/*
+ * Gate flags:
+ *   HW         means this gate can be auto-gated
+ *   SW         means the state of this gate can be software controlled
+ *   NO_DISABLE means this gate is (only) enabled if under software control
+ *   SW_MANAGED means the status of this gate is under software control
+ *   ENABLED    means this software-managed gate is *supposed* to be enabled
+ */
+#define BCM_CLK_GATE_FLAGS_EXISTS	((u32)1 << 0)	/* Gate is valid */
+#define BCM_CLK_GATE_FLAGS_HW		((u32)1 << 1)	/* Can auto-gate */
+#define BCM_CLK_GATE_FLAGS_SW		((u32)1 << 2)	/* Software control */
+#define BCM_CLK_GATE_FLAGS_NO_DISABLE	((u32)1 << 3)	/* HW or enabled */
+#define BCM_CLK_GATE_FLAGS_SW_MANAGED	((u32)1 << 4)	/* SW now in control */
+#define BCM_CLK_GATE_FLAGS_ENABLED	((u32)1 << 5)	/* If SW_MANAGED */
+
+/*
+ * Gate initialization macros.
+ *
+ * Any gate initially under software control will be enabled.
+ */
+
+/* A hardware/software gate initially under software control */
+#define HW_SW_GATE(_offset, _status_bit, _en_bit, _hw_sw_sel_bit)	\
+	{								\
+		.offset = (_offset),					\
+		.status_bit = (_status_bit),				\
+		.en_bit = (_en_bit),					\
+		.hw_sw_sel_bit = (_hw_sw_sel_bit),			\
+		.flags = FLAG(GATE, HW)|FLAG(GATE, SW)|			\
+			FLAG(GATE, SW_MANAGED)|FLAG(GATE, ENABLED)|	\
+			FLAG(GATE, EXISTS),				\
+	}
+
+/* A hardware/software gate initially under hardware control */
+#define HW_SW_GATE_AUTO(_offset, _status_bit, _en_bit, _hw_sw_sel_bit)	\
+	{								\
+		.offset = (_offset),					\
+		.status_bit = (_status_bit),				\
+		.en_bit = (_en_bit),					\
+		.hw_sw_sel_bit = (_hw_sw_sel_bit),			\
+		.flags = FLAG(GATE, HW)|FLAG(GATE, SW)|			\
+			FLAG(GATE, EXISTS),				\
+	}
+
+/* A hardware-or-enabled gate (enabled if not under hardware control) */
+#define HW_ENABLE_GATE(_offset, _status_bit, _en_bit, _hw_sw_sel_bit)	\
+	{								\
+		.offset = (_offset),					\
+		.status_bit = (_status_bit),				\
+		.en_bit = (_en_bit),					\
+		.hw_sw_sel_bit = (_hw_sw_sel_bit),			\
+		.flags = FLAG(GATE, HW)|FLAG(GATE, SW)|			\
+			FLAG(GATE, NO_DISABLE)|FLAG(GATE, EXISTS),	\
+	}
+
+/* A software-only gate */
+#define SW_ONLY_GATE(_offset, _status_bit, _en_bit)			\
+	{								\
+		.offset = (_offset),					\
+		.status_bit = (_status_bit),				\
+		.en_bit = (_en_bit),					\
+		.flags = FLAG(GATE, SW)|FLAG(GATE, SW_MANAGED)|		\
+			FLAG(GATE, ENABLED)|FLAG(GATE, EXISTS),		\
+	}
+
+/* A hardware-only gate */
+#define HW_ONLY_GATE(_offset, _status_bit)				\
+	{								\
+		.offset = (_offset),					\
+		.status_bit = (_status_bit),				\
+		.flags = FLAG(GATE, HW)|FLAG(GATE, EXISTS),		\
+	}
+
+/*
+ * Each clock can have zero, one, or two dividers which change the
+ * output rate of the clock.  Each divider can be either fixed or
+ * variable.  If there are two dividers, they are the "pre-divider"
+ * and the "regular" or "downstream" divider.  If there is only one,
+ * there is no pre-divider.
+ *
+ * A fixed divider is any non-zero (positive) value, and it
+ * indicates how the input rate is affected by the divider.
+ *
+ * The value of a variable divider is maintained in a sub-field of a
+ * 32-bit divider register.  The position of the field in the
+ * register is defined by its offset and width.  The value recorded
+ * in this field is always 1 less than the value it represents.
+ *
+ * In addition, a variable divider can indicate that some subset
+ * of its bits represent a "fractional" part of the divider.  Such
+ * bits comprise the low-order portion of the divider field, and can
+ * be viewed as representing the portion of the divider that lies to
+ * the right of the decimal point.  Most variable dividers have zero
+ * fractional bits.  Variable dividers with non-zero fraction width
+ * still record a value 1 less than the value they represent; the
+ * added 1 does *not* affect the low-order bit in this case, it
+ * affects the bits above the fractional part only.  (Often in this
+ * code a divider field value is distinguished from the value it
+ * represents by referring to the latter as a "divisor".)
+ *
+ * In order to avoid dealing with fractions, divider arithmetic is
+ * performed using "scaled" values.  A scaled value is one that's
+ * been left-shifted by the fractional width of a divider.  Dividing
+ * a scaled value by a scaled divisor produces the desired quotient
+ * without loss of precision and without any other special handling
+ * for fractions.
+ *
+ * The recorded value of a variable divider can be modified.  To
+ * modify either divider (or both), a clock must be enabled (i.e.,
+ * using its gate).  In addition, a trigger register (described
+ * below) must be used to commit the change, and polled to verify
+ * the change is complete.
+ */
+struct bcm_clk_div {
+	union {
+		struct {	/* variable divider */
+			u32 offset;	/* divider register offset */
+			u32 shift;	/* field shift */
+			u32 width;	/* field width */
+			u32 frac_width;	/* field fraction width */
+
+			u64 scaled_div;	/* scaled divider value */
+		};
+		u32 fixed;	/* non-zero fixed divider value */
+	};
+	u32 flags;		/* BCM_CLK_DIV_FLAGS_* below */
+};
+
+/*
+ * Divider flags:
+ *   EXISTS means this divider exists
+ *   FIXED means it is a fixed-rate divider
+ */
+#define BCM_CLK_DIV_FLAGS_EXISTS	((u32)1 << 0)	/* Divider is valid */
+#define BCM_CLK_DIV_FLAGS_FIXED		((u32)1 << 1)	/* Fixed-value */
+
+/* Divider initialization macros */
+
+/* A fixed (non-zero) divider */
+#define FIXED_DIVIDER(_value)						\
+	{								\
+		.fixed = (_value),					\
+		.flags = FLAG(DIV, EXISTS)|FLAG(DIV, FIXED),		\
+	}
+
+/* A divider with an integral divisor */
+#define DIVIDER(_offset, _shift, _width)				\
+	{								\
+		.offset = (_offset),					\
+		.shift = (_shift),					\
+		.width = (_width),					\
+		.scaled_div = BAD_SCALED_DIV_VALUE,			\
+		.flags = FLAG(DIV, EXISTS),				\
+	}
+
+/* A divider whose divisor has an integer and fractional part */
+#define FRAC_DIVIDER(_offset, _shift, _width, _frac_width)		\
+	{								\
+		.offset = (_offset),					\
+		.shift = (_shift),					\
+		.width = (_width),					\
+		.frac_width = (_frac_width),				\
+		.scaled_div = BAD_SCALED_DIV_VALUE,			\
+		.flags = FLAG(DIV, EXISTS),				\
+	}
+
+/*
+ * Clocks may have multiple "parent" clocks.  If there is more than
+ * one, a selector must be specified to define which of the parent
+ * clocks is currently in use.  The selected clock is indicated in a
+ * sub-field of a 32-bit selector register.  The range of
+ * representable selector values typically exceeds the number of
+ * available parent clocks.  Occasionally the reset value of a
+ * selector field is explicitly set to a (specific) value that does
+ * not correspond to a defined input clock.
+ *
+ * We register all known parent clocks with the common clock code
+ * using a packed array (i.e., no empty slots) of (parent) clock
+ * names, and refer to them later using indexes into that array.
+ * We maintain an array of selector values indexed by common clock
+ * index values in order to map between these common clock indexes
+ * and the selector values used by the hardware.
+ *
+ * Like dividers, a selector can be modified, but to do so a clock
+ * must be enabled, and a trigger must be used to commit the change.
+ */
+struct bcm_clk_sel {
+	u32 offset;		/* selector register offset */
+	u32 shift;		/* field shift */
+	u32 width;		/* field width */
+
+	u32 parent_count;	/* number of entries in parent_sel[] */
+	u32 *parent_sel;	/* array of parent selector values */
+	u8 clk_index;		/* current selected index in parent_sel[] */
+};
+
+/* Selector initialization macro */
+#define SELECTOR(_offset, _shift, _width)				\
+	{								\
+		.offset = (_offset),					\
+		.shift = (_shift),					\
+		.width = (_width),					\
+		.clk_index = BAD_CLK_INDEX,				\
+	}
+
+/*
+ * Making changes to a variable divider or a selector for a clock
+ * requires the use of a trigger.  A trigger is defined by a single
+ * bit within a register.  To signal a change, a 1 is written into
+ * that bit.  To determine when the change has been completed, that
+ * trigger bit is polled; the read value will be 1 while the change
+ * is in progress, and 0 when it is complete.
+ *
+ * Occasionally a clock will have more than one trigger.  In this
+ * case, the "pre-trigger" will be used when changing a clock's
+ * selector and/or its pre-divider.
+ */
+struct bcm_clk_trig {
+	u32 offset;		/* trigger register offset */
+	u32 bit;		/* trigger bit */
+	u32 flags;		/* BCM_CLK_TRIG_FLAGS_* below */
+};
+
+/*
+ * Trigger flags:
+ *   EXISTS means this trigger exists
+ */
+#define BCM_CLK_TRIG_FLAGS_EXISTS	((u32)1 << 0)	/* Trigger is valid */
+
+/* Trigger initialization macro */
+#define TRIGGER(_offset, _bit)						\
+	{								\
+		.offset = (_offset),					\
+		.bit = (_bit),						\
+		.flags = FLAG(TRIG, EXISTS),				\
+	}
+
+struct bus_clk_data {
+	struct bcm_clk_gate gate;
+};
+
+struct core_clk_data {
+	struct bcm_clk_gate gate;
+};
+
+struct peri_clk_data {
+	struct bcm_clk_gate gate;
+	struct bcm_clk_trig pre_trig;
+	struct bcm_clk_div pre_div;
+	struct bcm_clk_trig trig;
+	struct bcm_clk_div div;
+	struct bcm_clk_sel sel;
+	const char *clocks[];	/* must be last; use CLOCKS() to declare */
+};
+#define CLOCKS(...)	{ __VA_ARGS__, NULL, }
+#define NO_CLOCKS	{ NULL, }	/* Must use of no parent clocks */
+
+struct refclk {
+	struct clk clk;
+};
+
+struct peri_clock {
+	struct clk clk;
+	struct peri_clk_data *data;
+};
+
+struct ccu_clock {
+	struct clk clk;
+
+	int num_policy_masks;
+	unsigned long policy_freq_offset;
+	int freq_bit_shift;	/* 8 for most CCUs */
+	unsigned long policy_ctl_offset;
+	unsigned long policy0_mask_offset;
+	unsigned long policy1_mask_offset;
+	unsigned long policy2_mask_offset;
+	unsigned long policy3_mask_offset;
+	unsigned long policy0_mask2_offset;
+	unsigned long policy1_mask2_offset;
+	unsigned long policy2_mask2_offset;
+	unsigned long policy3_mask2_offset;
+	unsigned long lvm_en_offset;
+
+	int freq_id;
+	unsigned long *freq_tbl;
+};
+
+struct bus_clock {
+	struct clk clk;
+	struct bus_clk_data *data;
+	unsigned long *freq_tbl;
+};
+
+struct ref_clock {
+	struct clk clk;
+};
+
+static inline int is_same_clock(struct clk *a, struct clk *b)
+{
+	return (a == b);
+}
+
+#define to_clk(p) (&((p)->clk))
+#define name_to_clk(name) (&((name##_clk).clk))
+/* declare a struct clk_lookup */
+#define CLK_LK(name) \
+{.con_id = __stringify(name##_clk), .clk = name_to_clk(name),}
+
+static inline struct refclk *to_refclk(struct clk *clock)
+{
+	return container_of(clock, struct refclk, clk);
+}
+
+static inline struct peri_clock *to_peri_clk(struct clk *clock)
+{
+	return container_of(clock, struct peri_clock, clk);
+}
+
+static inline struct ccu_clock *to_ccu_clk(struct clk *clock)
+{
+	return container_of(clock, struct ccu_clock, clk);
+}
+
+static inline struct bus_clock *to_bus_clk(struct clk *clock)
+{
+	return container_of(clock, struct bus_clock, clk);
+}
+
+static inline struct ref_clock *to_ref_clk(struct clk *clock)
+{
+	return container_of(clock, struct ref_clock, clk);
+}
+
+extern struct clk_ops peri_clk_ops;
+extern struct clk_ops ccu_clk_ops;
+extern struct clk_ops bus_clk_ops;
+extern struct clk_ops ref_clk_ops;
+
+extern int clk_get_and_enable(char *clkstr);
diff --git a/arch/arm/cpu/armv7/bcm281xx/clk-sdio.c b/arch/arm/cpu/armv7/bcm281xx/clk-sdio.c
new file mode 100644
index 0000000..49badcb
--- /dev/null
+++ b/arch/arm/cpu/armv7/bcm281xx/clk-sdio.c
@@ -0,0 +1,73 @@
+/*
+ * Copyright 2013 Broadcom Corporation.
+ *
+ * SPDX-License-Identifier:      GPL-2.0+
+ */
+
+#include <common.h>
+#include <asm/io.h>
+#include <asm/errno.h>
+#include <asm/arch/sysmap.h>
+#include <asm/kona-common/clk.h>
+#include "clk-core.h"
+
+/* Enable appropriate clocks for an SDIO port */
+int clk_sdio_enable(void *base, u32 rate, u32 *actual_ratep)
+{
+	int ret;
+	struct clk *c;
+
+	char *clkstr;
+	char *slpstr;
+	char *ahbstr;
+
+	switch ((u32) base) {
+	case CONFIG_SYS_SDIO_BASE0:
+		clkstr = CONFIG_SYS_SDIO0 "_clk";
+		ahbstr = CONFIG_SYS_SDIO0 "_ahb_clk";
+		slpstr = CONFIG_SYS_SDIO0 "_sleep_clk";
+		break;
+	case CONFIG_SYS_SDIO_BASE1:
+		clkstr = CONFIG_SYS_SDIO1 "_clk";
+		ahbstr = CONFIG_SYS_SDIO1 "_ahb_clk";
+		slpstr = CONFIG_SYS_SDIO1 "_sleep_clk";
+		break;
+	case CONFIG_SYS_SDIO_BASE2:
+		clkstr = CONFIG_SYS_SDIO2 "_clk";
+		ahbstr = CONFIG_SYS_SDIO2 "_ahb_clk";
+		slpstr = CONFIG_SYS_SDIO2 "_sleep_clk";
+		break;
+	case CONFIG_SYS_SDIO_BASE3:
+		clkstr = CONFIG_SYS_SDIO3 "_clk";
+		ahbstr = CONFIG_SYS_SDIO3 "_ahb_clk";
+		slpstr = CONFIG_SYS_SDIO3 "_sleep_clk";
+		break;
+	default:
+		printf("%s: base 0x%p not found\n", __func__, base);
+		return -EINVAL;
+	}
+
+	ret = clk_get_and_enable(ahbstr);
+	if (ret)
+		return ret;
+
+	ret = clk_get_and_enable(slpstr);
+	if (ret)
+		return ret;
+
+	c = clk_get(clkstr);
+	if (c) {
+		ret = clk_set_rate(c, rate);
+		if (ret)
+			return ret;
+
+		ret = clk_enable(c);
+		if (ret)
+			return ret;
+	} else {
+		printf("%s: Couldn't find %s\n", __func__, clkstr);
+		return -EINVAL;
+	}
+	*actual_ratep = rate;
+	return 0;
+}
diff --git a/arch/arm/cpu/armv7/bcm281xx/reset.c b/arch/arm/cpu/armv7/bcm281xx/reset.c
new file mode 100644
index 0000000..3beb0ed
--- /dev/null
+++ b/arch/arm/cpu/armv7/bcm281xx/reset.c
@@ -0,0 +1,27 @@
+/*
+ * Copyright 2013 Broadcom Corporation.
+ *
+ * SPDX-License-Identifier:      GPL-2.0+
+ */
+
+#include <common.h>
+#include <asm/io.h>
+#include <asm/arch/sysmap.h>
+
+#define EN_MASK		0x08000000	/* Enable timer */
+#define SRSTEN_MASK	0x04000000	/* Enable soft reset */
+#define CLKS_SHIFT	20		/* Clock period shift */
+#define LD_SHIFT	0		/* Reload value shift */
+
+void reset_cpu(ulong ignored)
+{
+	/*
+	 * Set WD enable, RST enable,
+	 * 3.9 msec clock period (8), reload value (8*3.9ms)
+	 */
+	u32 reg = EN_MASK + SRSTEN_MASK + (8 << CLKS_SHIFT) + (8 << LD_SHIFT);
+	writel(reg, SECWD2_BASE_ADDR);
+
+	while (1)
+		;	/* loop forever till reset */
+}
diff --git a/arch/arm/cpu/armv7/kona-common/Makefile b/arch/arm/cpu/armv7/kona-common/Makefile
new file mode 100644
index 0000000..da225cb
--- /dev/null
+++ b/arch/arm/cpu/armv7/kona-common/Makefile
@@ -0,0 +1,9 @@
+#
+# Copyright 2013 Broadcom Corporation.
+#
+# SPDX-License-Identifier:	GPL-2.0+
+#
+
+obj-y	+= s_init.o
+obj-y	+= hwinit-common.o
+obj-y	+= clk-stubs.o
diff --git a/arch/arm/cpu/armv7/kona-common/clk-stubs.c b/arch/arm/cpu/armv7/kona-common/clk-stubs.c
new file mode 100644
index 0000000..338e0e4
--- /dev/null
+++ b/arch/arm/cpu/armv7/kona-common/clk-stubs.c
@@ -0,0 +1,21 @@
+/*
+ * Copyright 2013 Broadcom Corporation.
+ *
+ * SPDX-License-Identifier:      GPL-2.0+
+ */
+
+#include <common.h>
+
+/*
+ * These weak functions are available to kona architectures that don't
+ * require clock enables from the driver code.
+ */
+int __weak clk_sdio_enable(void *base, u32 rate, u32 *actual_ratep)
+{
+	return 0;
+}
+
+int __weak clk_bsc_enable(void *base, u32 rate, u32 *actual_ratep)
+{
+	return 0;
+}
diff --git a/arch/arm/cpu/armv7/kona-common/hwinit-common.c b/arch/arm/cpu/armv7/kona-common/hwinit-common.c
new file mode 100644
index 0000000..f8b1e06
--- /dev/null
+++ b/arch/arm/cpu/armv7/kona-common/hwinit-common.c
@@ -0,0 +1,16 @@
+/*
+ * Copyright 2013 Broadcom Corporation.
+ *
+ * SPDX-License-Identifier:      GPL-2.0+
+ */
+
+#include <common.h>
+#include <asm/sizes.h>
+
+#ifndef CONFIG_SYS_DCACHE_OFF
+void enable_caches(void)
+{
+	/* Enable D-cache. I-cache is already enabled in start.S */
+	dcache_enable();
+}
+#endif
diff --git a/arch/arm/cpu/armv7/kona-common/s_init.c b/arch/arm/cpu/armv7/kona-common/s_init.c
new file mode 100644
index 0000000..6066a73
--- /dev/null
+++ b/arch/arm/cpu/armv7/kona-common/s_init.c
@@ -0,0 +1,12 @@
+/*
+ * Copyright 2014 Broadcom Corporation.
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+
+/*
+ * Early system init. Currently empty.
+ */
+void s_init(void)
+{
+}
diff --git a/arch/arm/include/asm/arch-bcm281xx/gpio.h b/arch/arm/include/asm/arch-bcm281xx/gpio.h
new file mode 100644
index 0000000..1b40a96
--- /dev/null
+++ b/arch/arm/include/asm/arch-bcm281xx/gpio.h
@@ -0,0 +1,15 @@
+/*
+ * Copyright 2013 Broadcom Corporation.
+ *
+ * SPDX-License-Identifier:      GPL-2.0+
+ */
+
+#ifndef __ARCH_BCM281XX_GPIO_H
+#define __ARCH_BCM281XX_GPIO_H
+
+/*
+ * Empty file - cmd_gpio.c requires this. The implementation
+ * is in drivers/gpio/kona_gpio.c instead of inlined here.
+ */
+
+#endif
diff --git a/arch/arm/include/asm/arch-bcm281xx/sysmap.h b/arch/arm/include/asm/arch-bcm281xx/sysmap.h
new file mode 100644
index 0000000..880b4e0
--- /dev/null
+++ b/arch/arm/include/asm/arch-bcm281xx/sysmap.h
@@ -0,0 +1,25 @@
+/*
+ * Copyright 2013 Broadcom Corporation.
+ *
+ * SPDX-License-Identifier:      GPL-2.0+
+ */
+
+#ifndef __ARCH_BCM281XX_SYSMAP_H
+
+#define BSC1_BASE_ADDR		0x3e016000
+#define BSC2_BASE_ADDR		0x3e017000
+#define BSC3_BASE_ADDR		0x3e018000
+#define GPIO2_BASE_ADDR		0x35003000
+#define KONA_MST_CLK_BASE_ADDR	0x3f001000
+#define KONA_SLV_CLK_BASE_ADDR	0x3e011000
+#define PMU_BSC_BASE_ADDR	0x3500d000
+#define PWRMGR_BASE_ADDR	0x35010000
+#define SDIO1_BASE_ADDR		0x3f180000
+#define SDIO2_BASE_ADDR		0x3f190000
+#define SDIO3_BASE_ADDR		0x3f1a0000
+#define SDIO4_BASE_ADDR		0x3f1b0000
+#define SECWD_BASE_ADDR		0x3500c000
+#define SECWD2_BASE_ADDR	0x35002f40
+#define TIMER_BASE_ADDR		0x3e00d000
+
+#endif
diff --git a/arch/arm/include/asm/kona-common/clk.h b/arch/arm/include/asm/kona-common/clk.h
new file mode 100644
index 0000000..2c7e829
--- /dev/null
+++ b/arch/arm/include/asm/kona-common/clk.h
@@ -0,0 +1,29 @@
+/*
+ * Copyright 2013 Broadcom Corporation.
+ *
+ * SPDX-License-Identifier:      GPL-2.0+
+ */
+
+/* This API file is loosely based on u-boot/drivers/video/ipu.h and linux */
+
+#ifndef __KONA_COMMON_CLK_H
+#define __KONA_COMMON_CLK_H
+
+#include <linux/types.h>
+
+struct clk;
+
+/* Only implement required functions for your specific architecture */
+int clk_init(void);
+struct clk *clk_get(const char *id);
+int clk_enable(struct clk *clk);
+void clk_disable(struct clk *clk);
+unsigned long clk_get_rate(struct clk *clk);
+long clk_round_rate(struct clk *clk, unsigned long rate);
+int clk_set_rate(struct clk *clk, unsigned long rate);
+int clk_set_parent(struct clk *clk, struct clk *parent);
+struct clk *clk_get_parent(struct clk *clk);
+int clk_sdio_enable(void *base, u32 rate, u32 *actual_ratep);
+int clk_bsc_enable(void *base);
+
+#endif
diff --git a/arch/arm/include/asm/kona-common/kona_sdhci.h b/arch/arm/include/asm/kona-common/kona_sdhci.h
new file mode 100644
index 0000000..1ff0e55
--- /dev/null
+++ b/arch/arm/include/asm/kona-common/kona_sdhci.h
@@ -0,0 +1,12 @@
+/*
+ * Copyright 2013 Broadcom Corporation.
+ *
+ * SPDX-License-Identifier:      GPL-2.0+
+ */
+
+#ifndef __KONA_SDHCI_H
+#define __KONA_SDHCI_H
+
+int kona_sdhci_init(int dev_index, u32 min_clk, u32 quirks);
+
+#endif
diff --git a/board/broadcom/bcm28155_ap/Makefile b/board/broadcom/bcm28155_ap/Makefile
new file mode 100644
index 0000000..b18785a
--- /dev/null
+++ b/board/broadcom/bcm28155_ap/Makefile
@@ -0,0 +1,7 @@
+#
+# Copyright 2013 Broadcom Corporation.
+#
+# SPDX-License-Identifier:	GPL-2.0+
+#
+
+obj-y	+= $(BOARD).o
diff --git a/board/broadcom/bcm28155_ap/bcm28155_ap.c b/board/broadcom/bcm28155_ap/bcm28155_ap.c
new file mode 100644
index 0000000..940a1c2
--- /dev/null
+++ b/board/broadcom/bcm28155_ap/bcm28155_ap.c
@@ -0,0 +1,87 @@
+/*
+ * Copyright 2013 Broadcom Corporation.
+ *
+ * SPDX-License-Identifier:      GPL-2.0+
+ */
+
+#include <common.h>
+#include <asm/io.h>
+#include <asm/mach-types.h>
+#include <mmc.h>
+#include <asm/kona-common/kona_sdhci.h>
+#include <asm/kona-common/clk.h>
+#include <asm/arch/sysmap.h>
+
+#define SECWATCHDOG_SDOGCR_OFFSET	0x00000000
+#define SECWATCHDOG_SDOGCR_EN_SHIFT	27
+#define SECWATCHDOG_SDOGCR_SRSTEN_SHIFT	26
+#define SECWATCHDOG_SDOGCR_CLKS_SHIFT	20
+#define SECWATCHDOG_SDOGCR_LD_SHIFT	0
+
+DECLARE_GLOBAL_DATA_PTR;
+
+/*
+ * board_init - early hardware init
+ */
+int board_init(void)
+{
+	printf("Relocation Offset is: %08lx\n", gd->reloc_off);
+
+	/* adress of boot parameters */
+	gd->bd->bi_boot_params = CONFIG_SYS_SDRAM_BASE + 0x100;
+
+	clk_init();
+
+	return 0;
+}
+
+/*
+ * misc_init_r - miscellaneous platform dependent initializations
+ */
+int misc_init_r(void)
+{
+	/* Disable watchdog reset - watchdog unused */
+	writel((0 << SECWATCHDOG_SDOGCR_EN_SHIFT) |
+	       (0 << SECWATCHDOG_SDOGCR_SRSTEN_SHIFT) |
+	       (4 << SECWATCHDOG_SDOGCR_CLKS_SHIFT) |
+	       (0x5a0 << SECWATCHDOG_SDOGCR_LD_SHIFT),
+	       (SECWD_BASE_ADDR + SECWATCHDOG_SDOGCR_OFFSET));
+
+	return 0;
+}
+
+/*
+ * dram_init - sets uboots idea of sdram size
+ */
+int dram_init(void)
+{
+	gd->ram_size = get_ram_size((long *)CONFIG_SYS_SDRAM_BASE,
+				    CONFIG_SYS_SDRAM_SIZE);
+	return 0;
+}
+
+/* This is called after dram_init() so use get_ram_size result */
+void dram_init_banksize(void)
+{
+	gd->bd->bi_dram[0].start = CONFIG_SYS_SDRAM_BASE;
+	gd->bd->bi_dram[0].size = gd->ram_size;
+}
+
+#ifdef CONFIG_KONA_SDHCI
+/*
+ * mmc_init - Initializes mmc
+ */
+int board_mmc_init(bd_t *bis)
+{
+	int ret = 0;
+
+	/* Register eMMC - SDIO2 */
+	ret = kona_sdhci_init(1, 400000, 0);
+	if (ret)
+		return ret;
+
+	/* Register SD Card - SDIO4 kona_mmc_init assumes 0 based index */
+	ret = kona_sdhci_init(3, 400000, 0);
+	return ret;
+}
+#endif
diff --git a/boards.cfg b/boards.cfg
index 462e35b..872cb09 100644
--- a/boards.cfg
+++ b/boards.cfg
@@ -278,6 +278,7 @@
 Active  arm         armv7          at91        atmel           sama5d3xek          sama5d3xek_mmc                       sama5d3xek:SAMA5D3,SYS_USE_MMC                                                                                                    Bo Shen <voice.shen@atmel.com>
 Active  arm         armv7          at91        atmel           sama5d3xek          sama5d3xek_nandflash                 sama5d3xek:SAMA5D3,SYS_USE_NANDFLASH                                                                                              Bo Shen <voice.shen@atmel.com>
 Active  arm         armv7          at91        atmel           sama5d3xek          sama5d3xek_spiflash                  sama5d3xek:SAMA5D3,SYS_USE_SERIALFLASH                                                                                            Bo Shen <voice.shen@atmel.com>
+Active  arm         armv7          bcm281xx    broadcom        bcm28155_ap         bcm28155_ap                          bcm28155_ap                                                                                                                       Tim Kryger <tim.kryger@linaro.org>
 Active  arm         armv7          exynos      samsung         arndale             arndale                              -                                                                                                                                 Inderpal Singh <inderpal.singh@linaro.org>
 Active  arm         armv7          exynos      samsung         origen              origen                               -                                                                                                                                 Chander Kashyap <k.chander@samsung.com>
 Active  arm         armv7          exynos      samsung         smdk5250            smdk5250                             -                                                                                                                                 Chander Kashyap <k.chander@samsung.com>
diff --git a/common/cmd_pxe.c b/common/cmd_pxe.c
index 29e48db..3d13268 100644
--- a/common/cmd_pxe.c
+++ b/common/cmd_pxe.c
@@ -45,6 +45,7 @@
 	return ret;
 }
 
+#ifdef CONFIG_CMD_NET
 /*
  * Convert an ethaddr from the environment to the format used by pxelinux
  * filenames based on mac addresses. Convert's ':' to '-', and adds "01-" to
@@ -75,6 +76,7 @@
 
 	return 1;
 }
+#endif
 
 /*
  * Returns the directory the file specified in the bootfile env variable is
@@ -120,6 +122,7 @@
 
 static int (*do_getfile)(cmd_tbl_t *cmdtp, const char *file_path, char *file_addr);
 
+#ifdef CONFIG_CMD_NET
 static int do_get_tftp(cmd_tbl_t *cmdtp, const char *file_path, char *file_addr)
 {
 	char *tftp_argv[] = {"tftp", NULL, NULL, NULL};
@@ -132,6 +135,7 @@
 
 	return 1;
 }
+#endif
 
 static char *fs_argv[5];
 
@@ -249,6 +253,8 @@
 	return 1;
 }
 
+#ifdef CONFIG_CMD_NET
+
 #define PXELINUX_DIR "pxelinux.cfg/"
 
 /*
@@ -397,6 +403,7 @@
 
 	return 1;
 }
+#endif
 
 /*
  * Wrapper to make it easier to store the file at file_path in the location
@@ -647,6 +654,7 @@
 		len += strlen(ip_str);
 	}
 
+#ifdef CONFIG_CMD_NET
 	if (label->ipappend & 0x2) {
 		int err;
 		strcpy(mac_str, " BOOTIF=");
@@ -655,6 +663,7 @@
 			mac_str[0] = '\0';
 		len += strlen(mac_str);
 	}
+#endif
 
 	if (label->append)
 		len += strlen(label->append);
@@ -1500,6 +1509,7 @@
 	boot_unattempted_labels(cmdtp, cfg);
 }
 
+#ifdef CONFIG_CMD_NET
 /*
  * Boots a system using a pxe file
  *
@@ -1576,6 +1586,7 @@
 	"get - try to retrieve a pxe file using tftp\npxe "
 	"boot [pxefile_addr_r] - boot from the pxe file at pxefile_addr_r\n"
 );
+#endif
 
 /*
  * Boots a system using a local disk syslinux/extlinux file
diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile
index b903c45..ed2c0c7 100644
--- a/drivers/gpio/Makefile
+++ b/drivers/gpio/Makefile
@@ -8,6 +8,7 @@
 obj-$(CONFIG_AT91_GPIO)	+= at91_gpio.o
 obj-$(CONFIG_INTEL_ICH6_GPIO)	+= intel_ich6_gpio.o
 obj-$(CONFIG_KIRKWOOD_GPIO)	+= kw_gpio.o
+obj-$(CONFIG_KONA_GPIO)	+= kona_gpio.o
 obj-$(CONFIG_MARVELL_GPIO)	+= mvgpio.o
 obj-$(CONFIG_MARVELL_MFP)	+= mvmfp.o
 obj-$(CONFIG_MXC_GPIO)	+= mxc_gpio.o
diff --git a/drivers/gpio/kona_gpio.c b/drivers/gpio/kona_gpio.c
new file mode 100644
index 0000000..6511743
--- /dev/null
+++ b/drivers/gpio/kona_gpio.c
@@ -0,0 +1,141 @@
+/*
+ * Copyright 2013 Broadcom Corporation.
+ *
+ * SPDX-License-Identifier:      GPL-2.0+
+ */
+
+#include <common.h>
+#include <asm/io.h>
+#include <asm/arch/sysmap.h>
+
+#define GPIO_BASE				(void *)GPIO2_BASE_ADDR
+
+#define GPIO_PASSWD				0x00a5a501
+#define GPIO_PER_BANK				32
+#define GPIO_MAX_BANK_NUM			8
+
+#define GPIO_BANK(gpio)				((gpio) >> 5)
+#define GPIO_BITMASK(gpio)	\
+	(1UL << ((gpio) & (GPIO_PER_BANK - 1)))
+
+#define GPIO_OUT_STATUS(bank)			(0x00000000 + ((bank) << 2))
+#define GPIO_IN_STATUS(bank)			(0x00000020 + ((bank) << 2))
+#define GPIO_OUT_SET(bank)			(0x00000040 + ((bank) << 2))
+#define GPIO_OUT_CLEAR(bank)			(0x00000060 + ((bank) << 2))
+#define GPIO_INT_STATUS(bank)			(0x00000080 + ((bank) << 2))
+#define GPIO_INT_MASK(bank)			(0x000000a0 + ((bank) << 2))
+#define GPIO_INT_MSKCLR(bank)			(0x000000c0 + ((bank) << 2))
+#define GPIO_CONTROL(bank)			(0x00000100 + ((bank) << 2))
+#define GPIO_PWD_STATUS(bank)			(0x00000500 + ((bank) << 2))
+
+#define GPIO_GPPWR_OFFSET			0x00000520
+
+#define GPIO_GPCTR0_DBR_SHIFT			5
+#define GPIO_GPCTR0_DBR_MASK			0x000001e0
+
+#define GPIO_GPCTR0_ITR_SHIFT			3
+#define GPIO_GPCTR0_ITR_MASK			0x00000018
+#define GPIO_GPCTR0_ITR_CMD_RISING_EDGE		0x00000001
+#define GPIO_GPCTR0_ITR_CMD_FALLING_EDGE	0x00000002
+#define GPIO_GPCTR0_ITR_CMD_BOTH_EDGE		0x00000003
+
+#define GPIO_GPCTR0_IOTR_MASK			0x00000001
+#define GPIO_GPCTR0_IOTR_CMD_0UTPUT		0x00000000
+#define GPIO_GPCTR0_IOTR_CMD_INPUT		0x00000001
+
+int gpio_request(unsigned gpio, const char *label)
+{
+	unsigned int value, off;
+
+	writel(GPIO_PASSWD, GPIO_BASE + GPIO_GPPWR_OFFSET);
+	off = GPIO_PWD_STATUS(GPIO_BANK(gpio));
+	value = readl(GPIO_BASE + off) & ~GPIO_BITMASK(gpio);
+	writel(value, GPIO_BASE + off);
+
+	return 0;
+}
+
+int gpio_free(unsigned gpio)
+{
+	unsigned int value, off;
+
+	writel(GPIO_PASSWD, GPIO_BASE + GPIO_GPPWR_OFFSET);
+	off = GPIO_PWD_STATUS(GPIO_BANK(gpio));
+	value = readl(GPIO_BASE + off) | GPIO_BITMASK(gpio);
+	writel(value, GPIO_BASE + off);
+
+	return 0;
+}
+
+int gpio_direction_input(unsigned gpio)
+{
+	u32 val;
+
+	val = readl(GPIO_BASE + GPIO_CONTROL(gpio));
+	val &= ~GPIO_GPCTR0_IOTR_MASK;
+	val |= GPIO_GPCTR0_IOTR_CMD_INPUT;
+	writel(val, GPIO_BASE + GPIO_CONTROL(gpio));
+
+	return 0;
+}
+
+int gpio_direction_output(unsigned gpio, int value)
+{
+	int bank_id = GPIO_BANK(gpio);
+	int bitmask = GPIO_BITMASK(gpio);
+	u32 val, off;
+
+	val = readl(GPIO_BASE + GPIO_CONTROL(gpio));
+	val &= ~GPIO_GPCTR0_IOTR_MASK;
+	val |= GPIO_GPCTR0_IOTR_CMD_0UTPUT;
+	writel(val, GPIO_BASE + GPIO_CONTROL(gpio));
+	off = value ? GPIO_OUT_SET(bank_id) : GPIO_OUT_CLEAR(bank_id);
+
+	val = readl(GPIO_BASE + off);
+	val |= bitmask;
+	writel(val, GPIO_BASE + off);
+
+	return 0;
+}
+
+int gpio_get_value(unsigned gpio)
+{
+	int bank_id = GPIO_BANK(gpio);
+	int bitmask = GPIO_BITMASK(gpio);
+	u32 val, off;
+
+	/* determine the GPIO pin direction */
+	val = readl(GPIO_BASE + GPIO_CONTROL(gpio));
+	val &= GPIO_GPCTR0_IOTR_MASK;
+
+	/* read the GPIO bank status */
+	off = (GPIO_GPCTR0_IOTR_CMD_INPUT == val) ?
+	    GPIO_IN_STATUS(bank_id) : GPIO_OUT_STATUS(bank_id);
+	val = readl(GPIO_BASE + off);
+
+	/* return the specified bit status */
+	return !!(val & bitmask);
+}
+
+void gpio_set_value(unsigned gpio, int value)
+{
+	int bank_id = GPIO_BANK(gpio);
+	int bitmask = GPIO_BITMASK(gpio);
+	u32 val, off;
+
+	/* determine the GPIO pin direction */
+	val = readl(GPIO_BASE + GPIO_CONTROL(gpio));
+	val &= GPIO_GPCTR0_IOTR_MASK;
+
+	/* this function only applies to output pin */
+	if (GPIO_GPCTR0_IOTR_CMD_INPUT == val) {
+		printf("%s: Cannot set an input pin %d\n", __func__, gpio);
+		return;
+	}
+
+	off = value ? GPIO_OUT_SET(bank_id) : GPIO_OUT_CLEAR(bank_id);
+
+	val = readl(GPIO_BASE + off);
+	val |= bitmask;
+	writel(val, GPIO_BASE + off);
+}
diff --git a/drivers/i2c/Makefile b/drivers/i2c/Makefile
index fa3a875..36d5e5f 100644
--- a/drivers/i2c/Makefile
+++ b/drivers/i2c/Makefile
@@ -18,6 +18,7 @@
 obj-$(CONFIG_SYS_I2C) += i2c_core.o
 obj-$(CONFIG_SYS_I2C_FSL) += fsl_i2c.o
 obj-$(CONFIG_SYS_I2C_FTI2C010) += fti2c010.o
+obj-$(CONFIG_SYS_I2C_KONA) += kona_i2c.o
 obj-$(CONFIG_SYS_I2C_MXC) += mxc_i2c.o
 obj-$(CONFIG_SYS_I2C_OMAP24XX) += omap24xx_i2c.o
 obj-$(CONFIG_SYS_I2C_OMAP34XX) += omap24xx_i2c.o
diff --git a/drivers/i2c/kona_i2c.c b/drivers/i2c/kona_i2c.c
new file mode 100644
index 0000000..0b1715a
--- /dev/null
+++ b/drivers/i2c/kona_i2c.c
@@ -0,0 +1,730 @@
+/*
+ * Copyright 2013 Broadcom Corporation.
+ *
+ * SPDX-License-Identifier:      GPL-2.0+
+ */
+
+#include <common.h>
+#include <asm/io.h>
+#include <asm/errno.h>
+#include <asm/arch/sysmap.h>
+#include <asm/kona-common/clk.h>
+#include <i2c.h>
+
+/* Hardware register offsets and field defintions */
+#define CS_OFFSET				0x00000020
+#define CS_ACK_SHIFT				3
+#define CS_ACK_MASK				0x00000008
+#define CS_ACK_CMD_GEN_START			0x00000000
+#define CS_ACK_CMD_GEN_RESTART			0x00000001
+#define CS_CMD_SHIFT				1
+#define CS_CMD_CMD_NO_ACTION			0x00000000
+#define CS_CMD_CMD_START_RESTART		0x00000001
+#define CS_CMD_CMD_STOP				0x00000002
+#define CS_EN_SHIFT				0
+#define CS_EN_CMD_ENABLE_BSC			0x00000001
+
+#define TIM_OFFSET				0x00000024
+#define TIM_PRESCALE_SHIFT			6
+#define TIM_P_SHIFT				3
+#define TIM_NO_DIV_SHIFT			2
+#define TIM_DIV_SHIFT				0
+
+#define DAT_OFFSET				0x00000028
+
+#define TOUT_OFFSET				0x0000002c
+
+#define TXFCR_OFFSET				0x0000003c
+#define TXFCR_FIFO_FLUSH_MASK			0x00000080
+#define TXFCR_FIFO_EN_MASK			0x00000040
+
+#define IER_OFFSET				0x00000044
+#define IER_READ_COMPLETE_INT_MASK		0x00000010
+#define IER_I2C_INT_EN_MASK			0x00000008
+#define IER_FIFO_INT_EN_MASK			0x00000002
+#define IER_NOACK_EN_MASK			0x00000001
+
+#define ISR_OFFSET				0x00000048
+#define ISR_RESERVED_MASK			0xffffff60
+#define ISR_CMDBUSY_MASK			0x00000080
+#define ISR_READ_COMPLETE_MASK			0x00000010
+#define ISR_SES_DONE_MASK			0x00000008
+#define ISR_ERR_MASK				0x00000004
+#define ISR_TXFIFOEMPTY_MASK			0x00000002
+#define ISR_NOACK_MASK				0x00000001
+
+#define CLKEN_OFFSET				0x0000004c
+#define CLKEN_AUTOSENSE_OFF_MASK		0x00000080
+#define CLKEN_M_SHIFT				4
+#define CLKEN_N_SHIFT				1
+#define CLKEN_CLKEN_MASK			0x00000001
+
+#define FIFO_STATUS_OFFSET			0x00000054
+#define FIFO_STATUS_RXFIFO_EMPTY_MASK		0x00000004
+#define FIFO_STATUS_TXFIFO_EMPTY_MASK		0x00000010
+
+#define HSTIM_OFFSET				0x00000058
+#define HSTIM_HS_MODE_MASK			0x00008000
+#define HSTIM_HS_HOLD_SHIFT			10
+#define HSTIM_HS_HIGH_PHASE_SHIFT		5
+#define HSTIM_HS_SETUP_SHIFT			0
+
+#define PADCTL_OFFSET				0x0000005c
+#define PADCTL_PAD_OUT_EN_MASK			0x00000004
+
+#define RXFCR_OFFSET				0x00000068
+#define RXFCR_NACK_EN_SHIFT			7
+#define RXFCR_READ_COUNT_SHIFT			0
+#define RXFIFORDOUT_OFFSET			0x0000006c
+
+/* Locally used constants */
+#define MAX_RX_FIFO_SIZE		64U	/* bytes */
+#define MAX_TX_FIFO_SIZE		64U	/* bytes */
+
+#define I2C_TIMEOUT			100000	/* usecs */
+
+#define WAIT_INT_CHK			100	/* usecs */
+#if I2C_TIMEOUT % WAIT_INT_CHK
+#error I2C_TIMEOUT must be a multiple of WAIT_INT_CHK
+#endif
+
+/* Operations that can be commanded to the controller */
+enum bcm_kona_cmd_t {
+	BCM_CMD_NOACTION = 0,
+	BCM_CMD_START,
+	BCM_CMD_RESTART,
+	BCM_CMD_STOP,
+};
+
+enum bus_speed_index {
+	BCM_SPD_100K = 0,
+	BCM_SPD_400K,
+	BCM_SPD_1MHZ,
+};
+
+/* Internal divider settings for standard mode, fast mode and fast mode plus */
+struct bus_speed_cfg {
+	uint8_t time_m;		/* Number of cycles for setup time */
+	uint8_t time_n;		/* Number of cycles for hold time */
+	uint8_t prescale;	/* Prescale divider */
+	uint8_t time_p;		/* Timing coefficient */
+	uint8_t no_div;		/* Disable clock divider */
+	uint8_t time_div;	/* Post-prescale divider */
+};
+
+static const struct bus_speed_cfg std_cfg_table[] = {
+	[BCM_SPD_100K] = {0x01, 0x01, 0x03, 0x06, 0x00, 0x02},
+	[BCM_SPD_400K] = {0x05, 0x01, 0x03, 0x05, 0x01, 0x02},
+	[BCM_SPD_1MHZ] = {0x01, 0x01, 0x03, 0x01, 0x01, 0x03},
+};
+
+struct bcm_kona_i2c_dev {
+	void *base;
+	uint speed;
+	const struct bus_speed_cfg *std_cfg;
+};
+
+/* Keep these two defines in sync */
+#define DEF_SPD 100000
+#define DEF_SPD_ENUM BCM_SPD_100K
+
+#define DEF_DEVICE(num) \
+{(void *)CONFIG_SYS_I2C_BASE##num, DEF_SPD, &std_cfg_table[DEF_SPD_ENUM]}
+
+static struct bcm_kona_i2c_dev g_i2c_devs[CONFIG_SYS_MAX_I2C_BUS] = {
+#ifdef CONFIG_SYS_I2C_BASE0
+	DEF_DEVICE(0),
+#endif
+#ifdef CONFIG_SYS_I2C_BASE1
+	DEF_DEVICE(1),
+#endif
+#ifdef CONFIG_SYS_I2C_BASE2
+	DEF_DEVICE(2),
+#endif
+#ifdef CONFIG_SYS_I2C_BASE3
+	DEF_DEVICE(3),
+#endif
+#ifdef CONFIG_SYS_I2C_BASE4
+	DEF_DEVICE(4),
+#endif
+#ifdef CONFIG_SYS_I2C_BASE5
+	DEF_DEVICE(5),
+#endif
+};
+
+#define I2C_M_TEN	0x0010	/* ten bit address */
+#define I2C_M_RD	0x0001	/* read data */
+#define I2C_M_NOSTART	0x4000	/* no restart between msgs */
+
+struct i2c_msg {
+	uint16_t addr;
+	uint16_t flags;
+	uint16_t len;
+	uint8_t *buf;
+};
+
+static void bcm_kona_i2c_send_cmd_to_ctrl(struct bcm_kona_i2c_dev *dev,
+					  enum bcm_kona_cmd_t cmd)
+{
+	debug("%s, %d\n", __func__, cmd);
+
+	switch (cmd) {
+	case BCM_CMD_NOACTION:
+		writel((CS_CMD_CMD_NO_ACTION << CS_CMD_SHIFT) |
+		       (CS_EN_CMD_ENABLE_BSC << CS_EN_SHIFT),
+		       dev->base + CS_OFFSET);
+		break;
+
+	case BCM_CMD_START:
+		writel((CS_ACK_CMD_GEN_START << CS_ACK_SHIFT) |
+		       (CS_CMD_CMD_START_RESTART << CS_CMD_SHIFT) |
+		       (CS_EN_CMD_ENABLE_BSC << CS_EN_SHIFT),
+		       dev->base + CS_OFFSET);
+		break;
+
+	case BCM_CMD_RESTART:
+		writel((CS_ACK_CMD_GEN_RESTART << CS_ACK_SHIFT) |
+		       (CS_CMD_CMD_START_RESTART << CS_CMD_SHIFT) |
+		       (CS_EN_CMD_ENABLE_BSC << CS_EN_SHIFT),
+		       dev->base + CS_OFFSET);
+		break;
+
+	case BCM_CMD_STOP:
+		writel((CS_CMD_CMD_STOP << CS_CMD_SHIFT) |
+		       (CS_EN_CMD_ENABLE_BSC << CS_EN_SHIFT),
+		       dev->base + CS_OFFSET);
+		break;
+
+	default:
+		printf("Unknown command %d\n", cmd);
+	}
+}
+
+static void bcm_kona_i2c_enable_clock(struct bcm_kona_i2c_dev *dev)
+{
+	writel(readl(dev->base + CLKEN_OFFSET) | CLKEN_CLKEN_MASK,
+	       dev->base + CLKEN_OFFSET);
+}
+
+static void bcm_kona_i2c_disable_clock(struct bcm_kona_i2c_dev *dev)
+{
+	writel(readl(dev->base + CLKEN_OFFSET) & ~CLKEN_CLKEN_MASK,
+	       dev->base + CLKEN_OFFSET);
+}
+
+/* Wait until at least one of the mask bit(s) are set */
+static unsigned long wait_for_int_timeout(struct bcm_kona_i2c_dev *dev,
+					  unsigned long time_left,
+					  uint32_t mask)
+{
+	uint32_t status;
+
+	while (time_left) {
+		status = readl(dev->base + ISR_OFFSET);
+
+		if ((status & ~ISR_RESERVED_MASK) == 0) {
+			debug("Bogus I2C interrupt 0x%x\n", status);
+			continue;
+		}
+
+		/* Must flush the TX FIFO when NAK detected */
+		if (status & ISR_NOACK_MASK)
+			writel(TXFCR_FIFO_FLUSH_MASK | TXFCR_FIFO_EN_MASK,
+			       dev->base + TXFCR_OFFSET);
+
+		writel(status & ~ISR_RESERVED_MASK, dev->base + ISR_OFFSET);
+
+		if (status & mask) {
+			/* We are done since one of the mask bits are set */
+			return time_left;
+		}
+		udelay(WAIT_INT_CHK);
+		time_left -= WAIT_INT_CHK;
+	}
+	return 0;
+}
+
+/* Send command to I2C bus */
+static int bcm_kona_send_i2c_cmd(struct bcm_kona_i2c_dev *dev,
+				 enum bcm_kona_cmd_t cmd)
+{
+	int rc = 0;
+	unsigned long time_left = I2C_TIMEOUT;
+
+	/* Send the command */
+	bcm_kona_i2c_send_cmd_to_ctrl(dev, cmd);
+
+	/* Wait for transaction to finish or timeout */
+	time_left = wait_for_int_timeout(dev, time_left, IER_I2C_INT_EN_MASK);
+
+	if (!time_left) {
+		printf("controller timed out\n");
+		rc = -ETIMEDOUT;
+	}
+
+	/* Clear command */
+	bcm_kona_i2c_send_cmd_to_ctrl(dev, BCM_CMD_NOACTION);
+
+	return rc;
+}
+
+/* Read a single RX FIFO worth of data from the i2c bus */
+static int bcm_kona_i2c_read_fifo_single(struct bcm_kona_i2c_dev *dev,
+					 uint8_t *buf, unsigned int len,
+					 unsigned int last_byte_nak)
+{
+	unsigned long time_left = I2C_TIMEOUT;
+
+	/* Start the RX FIFO */
+	writel((last_byte_nak << RXFCR_NACK_EN_SHIFT) |
+	       (len << RXFCR_READ_COUNT_SHIFT), dev->base + RXFCR_OFFSET);
+
+	/* Wait for FIFO read to complete */
+	time_left =
+	    wait_for_int_timeout(dev, time_left, IER_READ_COMPLETE_INT_MASK);
+
+	if (!time_left) {
+		printf("RX FIFO time out\n");
+		return -EREMOTEIO;
+	}
+
+	/* Read data from FIFO */
+	for (; len > 0; len--, buf++)
+		*buf = readl(dev->base + RXFIFORDOUT_OFFSET);
+
+	return 0;
+}
+
+/* Read any amount of data using the RX FIFO from the i2c bus */
+static int bcm_kona_i2c_read_fifo(struct bcm_kona_i2c_dev *dev,
+				  struct i2c_msg *msg)
+{
+	unsigned int bytes_to_read = MAX_RX_FIFO_SIZE;
+	unsigned int last_byte_nak = 0;
+	unsigned int bytes_read = 0;
+	int rc;
+
+	uint8_t *tmp_buf = msg->buf;
+
+	while (bytes_read < msg->len) {
+		if (msg->len - bytes_read <= MAX_RX_FIFO_SIZE) {
+			last_byte_nak = 1;	/* NAK last byte of transfer */
+			bytes_to_read = msg->len - bytes_read;
+		}
+
+		rc = bcm_kona_i2c_read_fifo_single(dev, tmp_buf, bytes_to_read,
+						   last_byte_nak);
+		if (rc < 0)
+			return -EREMOTEIO;
+
+		bytes_read += bytes_to_read;
+		tmp_buf += bytes_to_read;
+	}
+
+	return 0;
+}
+
+/* Write a single byte of data to the i2c bus */
+static int bcm_kona_i2c_write_byte(struct bcm_kona_i2c_dev *dev, uint8_t data,
+				   unsigned int nak_expected)
+{
+	unsigned long time_left = I2C_TIMEOUT;
+	unsigned int nak_received;
+
+	/* Clear pending session done interrupt */
+	writel(ISR_SES_DONE_MASK, dev->base + ISR_OFFSET);
+
+	/* Send one byte of data */
+	writel(data, dev->base + DAT_OFFSET);
+
+	time_left = wait_for_int_timeout(dev, time_left, IER_I2C_INT_EN_MASK);
+
+	if (!time_left) {
+		debug("controller timed out\n");
+		return -ETIMEDOUT;
+	}
+
+	nak_received = readl(dev->base + CS_OFFSET) & CS_ACK_MASK ? 1 : 0;
+
+	if (nak_received ^ nak_expected) {
+		debug("unexpected NAK/ACK\n");
+		return -EREMOTEIO;
+	}
+
+	return 0;
+}
+
+/* Write a single TX FIFO worth of data to the i2c bus */
+static int bcm_kona_i2c_write_fifo_single(struct bcm_kona_i2c_dev *dev,
+					  uint8_t *buf, unsigned int len)
+{
+	int k;
+	unsigned long time_left = I2C_TIMEOUT;
+	unsigned int fifo_status;
+
+	/* Write data into FIFO */
+	for (k = 0; k < len; k++)
+		writel(buf[k], (dev->base + DAT_OFFSET));
+
+	/* Wait for FIFO to empty */
+	do {
+		time_left =
+		    wait_for_int_timeout(dev, time_left,
+					 (IER_FIFO_INT_EN_MASK |
+					  IER_NOACK_EN_MASK));
+		fifo_status = readl(dev->base + FIFO_STATUS_OFFSET);
+	} while (time_left && !(fifo_status & FIFO_STATUS_TXFIFO_EMPTY_MASK));
+
+	/* Check if there was a NAK */
+	if (readl(dev->base + CS_OFFSET) & CS_ACK_MASK) {
+		printf("unexpected NAK\n");
+		return -EREMOTEIO;
+	}
+
+	/* Check if a timeout occured */
+	if (!time_left) {
+		printf("completion timed out\n");
+		return -EREMOTEIO;
+	}
+
+	return 0;
+}
+
+/* Write any amount of data using TX FIFO to the i2c bus */
+static int bcm_kona_i2c_write_fifo(struct bcm_kona_i2c_dev *dev,
+				   struct i2c_msg *msg)
+{
+	unsigned int bytes_to_write = MAX_TX_FIFO_SIZE;
+	unsigned int bytes_written = 0;
+	int rc;
+
+	uint8_t *tmp_buf = msg->buf;
+
+	while (bytes_written < msg->len) {
+		if (msg->len - bytes_written <= MAX_TX_FIFO_SIZE)
+			bytes_to_write = msg->len - bytes_written;
+
+		rc = bcm_kona_i2c_write_fifo_single(dev, tmp_buf,
+						    bytes_to_write);
+		if (rc < 0)
+			return -EREMOTEIO;
+
+		bytes_written += bytes_to_write;
+		tmp_buf += bytes_to_write;
+	}
+
+	return 0;
+}
+
+/* Send i2c address */
+static int bcm_kona_i2c_do_addr(struct bcm_kona_i2c_dev *dev,
+				struct i2c_msg *msg)
+{
+	unsigned char addr;
+
+	if (msg->flags & I2C_M_TEN) {
+		/* First byte is 11110XX0 where XX is upper 2 bits */
+		addr = 0xf0 | ((msg->addr & 0x300) >> 7);
+		if (bcm_kona_i2c_write_byte(dev, addr, 0) < 0)
+			return -EREMOTEIO;
+
+		/* Second byte is the remaining 8 bits */
+		addr = msg->addr & 0xff;
+		if (bcm_kona_i2c_write_byte(dev, addr, 0) < 0)
+			return -EREMOTEIO;
+
+		if (msg->flags & I2C_M_RD) {
+			/* For read, send restart command */
+			if (bcm_kona_send_i2c_cmd(dev, BCM_CMD_RESTART) < 0)
+				return -EREMOTEIO;
+
+			/* Then re-send the first byte with the read bit set */
+			addr = 0xf0 | ((msg->addr & 0x300) >> 7) | 0x01;
+			if (bcm_kona_i2c_write_byte(dev, addr, 0) < 0)
+				return -EREMOTEIO;
+		}
+	} else {
+		addr = msg->addr << 1;
+
+		if (msg->flags & I2C_M_RD)
+			addr |= 1;
+
+		if (bcm_kona_i2c_write_byte(dev, addr, 0) < 0)
+			return -EREMOTEIO;
+	}
+
+	return 0;
+}
+
+static void bcm_kona_i2c_enable_autosense(struct bcm_kona_i2c_dev *dev)
+{
+	writel(readl(dev->base + CLKEN_OFFSET) & ~CLKEN_AUTOSENSE_OFF_MASK,
+	       dev->base + CLKEN_OFFSET);
+}
+
+static void bcm_kona_i2c_config_timing(struct bcm_kona_i2c_dev *dev)
+{
+	writel(readl(dev->base + HSTIM_OFFSET) & ~HSTIM_HS_MODE_MASK,
+	       dev->base + HSTIM_OFFSET);
+
+	writel((dev->std_cfg->prescale << TIM_PRESCALE_SHIFT) |
+	       (dev->std_cfg->time_p << TIM_P_SHIFT) |
+	       (dev->std_cfg->no_div << TIM_NO_DIV_SHIFT) |
+	       (dev->std_cfg->time_div << TIM_DIV_SHIFT),
+	       dev->base + TIM_OFFSET);
+
+	writel((dev->std_cfg->time_m << CLKEN_M_SHIFT) |
+	       (dev->std_cfg->time_n << CLKEN_N_SHIFT) |
+	       CLKEN_CLKEN_MASK, dev->base + CLKEN_OFFSET);
+}
+
+/* Master transfer function */
+static int bcm_kona_i2c_xfer(struct bcm_kona_i2c_dev *dev,
+			     struct i2c_msg msgs[], int num)
+{
+	struct i2c_msg *pmsg;
+	int rc = 0;
+	int i;
+
+	/* Enable pad output */
+	writel(0, dev->base + PADCTL_OFFSET);
+
+	/* Enable internal clocks */
+	bcm_kona_i2c_enable_clock(dev);
+
+	/* Send start command */
+	rc = bcm_kona_send_i2c_cmd(dev, BCM_CMD_START);
+	if (rc < 0) {
+		printf("Start command failed rc = %d\n", rc);
+		goto xfer_disable_pad;
+	}
+
+	/* Loop through all messages */
+	for (i = 0; i < num; i++) {
+		pmsg = &msgs[i];
+
+		/* Send restart for subsequent messages */
+		if ((i != 0) && ((pmsg->flags & I2C_M_NOSTART) == 0)) {
+			rc = bcm_kona_send_i2c_cmd(dev, BCM_CMD_RESTART);
+			if (rc < 0) {
+				printf("restart cmd failed rc = %d\n", rc);
+				goto xfer_send_stop;
+			}
+		}
+
+		/* Send slave address */
+		if (!(pmsg->flags & I2C_M_NOSTART)) {
+			rc = bcm_kona_i2c_do_addr(dev, pmsg);
+			if (rc < 0) {
+				debug("NAK from addr %2.2x msg#%d rc = %d\n",
+				      pmsg->addr, i, rc);
+				goto xfer_send_stop;
+			}
+		}
+
+		/* Perform data transfer */
+		if (pmsg->flags & I2C_M_RD) {
+			rc = bcm_kona_i2c_read_fifo(dev, pmsg);
+			if (rc < 0) {
+				printf("read failure\n");
+				goto xfer_send_stop;
+			}
+		} else {
+			rc = bcm_kona_i2c_write_fifo(dev, pmsg);
+			if (rc < 0) {
+				printf("write failure");
+				goto xfer_send_stop;
+			}
+		}
+	}
+
+	rc = num;
+
+xfer_send_stop:
+	/* Send a STOP command */
+	bcm_kona_send_i2c_cmd(dev, BCM_CMD_STOP);
+
+xfer_disable_pad:
+	/* Disable pad output */
+	writel(PADCTL_PAD_OUT_EN_MASK, dev->base + PADCTL_OFFSET);
+
+	/* Stop internal clock */
+	bcm_kona_i2c_disable_clock(dev);
+
+	return rc;
+}
+
+static uint bcm_kona_i2c_assign_bus_speed(struct bcm_kona_i2c_dev *dev,
+					  uint speed)
+{
+	switch (speed) {
+	case 100000:
+		dev->std_cfg = &std_cfg_table[BCM_SPD_100K];
+		break;
+	case 400000:
+		dev->std_cfg = &std_cfg_table[BCM_SPD_400K];
+		break;
+	case 1000000:
+		dev->std_cfg = &std_cfg_table[BCM_SPD_1MHZ];
+		break;
+	default:
+		printf("%d hz bus speed not supported\n", speed);
+		return -EINVAL;
+	}
+	dev->speed = speed;
+	return 0;
+}
+
+static void bcm_kona_i2c_init(struct bcm_kona_i2c_dev *dev)
+{
+	/* Parse bus speed */
+	bcm_kona_i2c_assign_bus_speed(dev, dev->speed);
+
+	/* Enable internal clocks */
+	bcm_kona_i2c_enable_clock(dev);
+
+	/* Configure internal dividers */
+	bcm_kona_i2c_config_timing(dev);
+
+	/* Disable timeout */
+	writel(0, dev->base + TOUT_OFFSET);
+
+	/* Enable autosense */
+	bcm_kona_i2c_enable_autosense(dev);
+
+	/* Enable TX FIFO */
+	writel(TXFCR_FIFO_FLUSH_MASK | TXFCR_FIFO_EN_MASK,
+	       dev->base + TXFCR_OFFSET);
+
+	/* Mask all interrupts */
+	writel(0, dev->base + IER_OFFSET);
+
+	/* Clear all pending interrupts */
+	writel(ISR_CMDBUSY_MASK |
+	       ISR_READ_COMPLETE_MASK |
+	       ISR_SES_DONE_MASK |
+	       ISR_ERR_MASK |
+	       ISR_TXFIFOEMPTY_MASK | ISR_NOACK_MASK, dev->base + ISR_OFFSET);
+
+	/* Enable the controller but leave it idle */
+	bcm_kona_i2c_send_cmd_to_ctrl(dev, BCM_CMD_NOACTION);
+
+	/* Disable pad output */
+	writel(PADCTL_PAD_OUT_EN_MASK, dev->base + PADCTL_OFFSET);
+}
+
+/*
+ * uboot layer
+ */
+struct bcm_kona_i2c_dev *kona_get_dev(struct i2c_adapter *adap)
+{
+	return &g_i2c_devs[adap->hwadapnr];
+}
+
+static void kona_i2c_init(struct i2c_adapter *adap, int speed, int slaveaddr)
+{
+	struct bcm_kona_i2c_dev *dev = kona_get_dev(adap);
+
+	if (clk_bsc_enable(dev->base))
+		return;
+
+	bcm_kona_i2c_init(dev);
+}
+
+static int kona_i2c_read(struct i2c_adapter *adap, uchar chip, uint addr,
+			 int alen, uchar *buffer, int len)
+{
+	/* msg[0] writes the addr, msg[1] reads the data */
+	struct i2c_msg msg[2];
+	unsigned char msgbuf0[64];
+	struct bcm_kona_i2c_dev *dev = kona_get_dev(adap);
+
+	msg[0].addr = chip;
+	msg[0].flags = 0;
+	msg[0].len = 1;
+	msg[0].buf = msgbuf0;	/* msgbuf0 contains incrementing reg addr */
+
+	msg[1].addr = chip;
+	msg[1].flags = I2C_M_RD;
+	/* msg[1].buf dest ptr increments each read */
+
+	msgbuf0[0] = (unsigned char)addr;
+	msg[1].buf = buffer;
+	msg[1].len = len;
+	if (bcm_kona_i2c_xfer(dev, msg, 2) < 0) {
+		/* Sending 2 i2c messages */
+		kona_i2c_init(adap, adap->speed, adap->slaveaddr);
+		debug("I2C read: I/O error\n");
+		return -EIO;
+	}
+	return 0;
+}
+
+static int kona_i2c_write(struct i2c_adapter *adap, uchar chip, uint addr,
+			  int alen, uchar *buffer, int len)
+{
+	struct i2c_msg msg[0];
+	unsigned char msgbuf0[64];
+	unsigned int i;
+	struct bcm_kona_i2c_dev *dev = kona_get_dev(adap);
+
+	msg[0].addr = chip;
+	msg[0].flags = 0;
+	msg[0].len = 2;		/* addr byte plus data */
+	msg[0].buf = msgbuf0;
+
+	for (i = 0; i < len; i++) {
+		msgbuf0[0] = addr++;
+		msgbuf0[1] = buffer[i];
+		if (bcm_kona_i2c_xfer(dev, msg, 1) < 0) {
+			kona_i2c_init(adap, adap->speed, adap->slaveaddr);
+			debug("I2C write: I/O error\n");
+			return -EIO;
+		}
+	}
+	return 0;
+}
+
+static int kona_i2c_probe(struct i2c_adapter *adap, uchar chip)
+{
+	uchar tmp;
+
+	/*
+	 * read addr 0x0 of the given chip.
+	 */
+	return kona_i2c_read(adap, chip, 0x0, 1, &tmp, 1);
+}
+
+static uint kona_i2c_set_bus_speed(struct i2c_adapter *adap, uint speed)
+{
+	struct bcm_kona_i2c_dev *dev = kona_get_dev(adap);
+	return bcm_kona_i2c_assign_bus_speed(dev, speed);
+}
+
+/*
+ * Register kona i2c adapters. Keep the order below so
+ * that the bus number matches the adapter number.
+ */
+#define DEF_ADAPTER(num) \
+U_BOOT_I2C_ADAP_COMPLETE(kona##num, kona_i2c_init, kona_i2c_probe, \
+			 kona_i2c_read, kona_i2c_write, \
+			 kona_i2c_set_bus_speed, DEF_SPD, 0x00, num)
+
+#ifdef CONFIG_SYS_I2C_BASE0
+	DEF_ADAPTER(0)
+#endif
+#ifdef CONFIG_SYS_I2C_BASE1
+	DEF_ADAPTER(1)
+#endif
+#ifdef CONFIG_SYS_I2C_BASE2
+	DEF_ADAPTER(2)
+#endif
+#ifdef CONFIG_SYS_I2C_BASE3
+	DEF_ADAPTER(3)
+#endif
+#ifdef CONFIG_SYS_I2C_BASE4
+	DEF_ADAPTER(4)
+#endif
+#ifdef CONFIG_SYS_I2C_BASE5
+	DEF_ADAPTER(5)
+#endif
diff --git a/drivers/mmc/Makefile b/drivers/mmc/Makefile
index e793ed9..931922b 100644
--- a/drivers/mmc/Makefile
+++ b/drivers/mmc/Makefile
@@ -21,6 +21,7 @@
 obj-$(CONFIG_PXA_MMC_GENERIC) += pxa_mmc_gen.o
 obj-$(CONFIG_SDHCI) += sdhci.o
 obj-$(CONFIG_BCM2835_SDHCI) += bcm2835_sdhci.o
+obj-$(CONFIG_KONA_SDHCI) += kona_sdhci.o
 obj-$(CONFIG_S5P_SDHCI) += s5p_sdhci.o
 obj-$(CONFIG_SH_MMCIF) += sh_mmcif.o
 obj-$(CONFIG_SPEAR_SDHCI) += spear_sdhci.o
diff --git a/drivers/mmc/kona_sdhci.c b/drivers/mmc/kona_sdhci.c
new file mode 100644
index 0000000..77e42c8
--- /dev/null
+++ b/drivers/mmc/kona_sdhci.c
@@ -0,0 +1,134 @@
+/*
+ * Copyright 2013 Broadcom Corporation.
+ *
+ * SPDX-License-Identifier:      GPL-2.0+
+ */
+
+#include <common.h>
+#include <malloc.h>
+#include <sdhci.h>
+#include <asm/errno.h>
+#include <asm/kona-common/clk.h>
+
+#define SDHCI_CORECTRL_OFFSET		0x00008000
+#define SDHCI_CORECTRL_EN		0x01
+#define SDHCI_CORECTRL_RESET		0x02
+
+#define SDHCI_CORESTAT_OFFSET		0x00008004
+#define SDHCI_CORESTAT_CD_SW		0x01
+
+#define SDHCI_COREIMR_OFFSET		0x00008008
+#define SDHCI_COREIMR_IP		0x01
+
+static int init_kona_mmc_core(struct sdhci_host *host)
+{
+	unsigned int mask;
+	unsigned int timeout;
+
+	if (sdhci_readb(host, SDHCI_SOFTWARE_RESET) & SDHCI_RESET_ALL) {
+		printf("%s: sd host controller reset error\n", __func__);
+		return 1;
+	}
+
+	/* For kona a hardware reset before anything else. */
+	mask = sdhci_readl(host, SDHCI_CORECTRL_OFFSET) | SDHCI_CORECTRL_RESET;
+	sdhci_writel(host, mask, SDHCI_CORECTRL_OFFSET);
+
+	/* Wait max 100 ms */
+	timeout = 1000;
+	do {
+		if (timeout == 0) {
+			printf("%s: reset timeout error\n", __func__);
+			return 1;
+		}
+		timeout--;
+		udelay(100);
+	} while (0 ==
+		 (sdhci_readl(host, SDHCI_CORECTRL_OFFSET) &
+		  SDHCI_CORECTRL_RESET));
+
+	/* Clear the reset bit. */
+	mask = mask & ~SDHCI_CORECTRL_RESET;
+	sdhci_writel(host, mask, SDHCI_CORECTRL_OFFSET);
+
+	/* Enable AHB clock */
+	mask = sdhci_readl(host, SDHCI_CORECTRL_OFFSET);
+	sdhci_writel(host, mask | SDHCI_CORECTRL_EN, SDHCI_CORECTRL_OFFSET);
+
+	/* Enable interrupts */
+	sdhci_writel(host, SDHCI_COREIMR_IP, SDHCI_COREIMR_OFFSET);
+
+	/* Make sure Card is detected in controller */
+	mask = sdhci_readl(host, SDHCI_CORESTAT_OFFSET);
+	sdhci_writel(host, mask | SDHCI_CORESTAT_CD_SW, SDHCI_CORESTAT_OFFSET);
+
+	/* Wait max 100 ms */
+	timeout = 1000;
+	while (!(sdhci_readl(host, SDHCI_PRESENT_STATE) & SDHCI_CARD_PRESENT)) {
+		if (timeout == 0) {
+			printf("%s: CARD DETECT timeout error\n", __func__);
+			return 1;
+		}
+		timeout--;
+		udelay(100);
+	}
+	return 0;
+}
+
+int kona_sdhci_init(int dev_index, u32 min_clk, u32 quirks)
+{
+	int ret = 0;
+	u32 max_clk;
+	void *reg_base;
+	struct sdhci_host *host = NULL;
+
+	host = (struct sdhci_host *)malloc(sizeof(struct sdhci_host));
+	if (!host) {
+		printf("%s: sdhci host malloc fail!\n", __func__);
+		return -ENOMEM;
+	}
+	switch (dev_index) {
+	case 0:
+		reg_base = (void *)CONFIG_SYS_SDIO_BASE0;
+		ret = clk_sdio_enable(reg_base, CONFIG_SYS_SDIO0_MAX_CLK,
+				      &max_clk);
+		break;
+	case 1:
+		reg_base = (void *)CONFIG_SYS_SDIO_BASE1;
+		ret = clk_sdio_enable(reg_base, CONFIG_SYS_SDIO1_MAX_CLK,
+				      &max_clk);
+		break;
+	case 2:
+		reg_base = (void *)CONFIG_SYS_SDIO_BASE2;
+		ret = clk_sdio_enable(reg_base, CONFIG_SYS_SDIO2_MAX_CLK,
+				      &max_clk);
+		break;
+	case 3:
+		reg_base = (void *)CONFIG_SYS_SDIO_BASE3;
+		ret = clk_sdio_enable(reg_base, CONFIG_SYS_SDIO3_MAX_CLK,
+				      &max_clk);
+		break;
+	default:
+		printf("%s: sdio dev index %d not supported\n",
+		       __func__, dev_index);
+		ret = -EINVAL;
+	}
+	if (ret)
+		return ret;
+
+	host->name = "kona-sdhci";
+	host->ioaddr = reg_base;
+	host->quirks = quirks;
+	host->host_caps = MMC_MODE_HC;
+
+	if (init_kona_mmc_core(host))
+		return -EINVAL;
+
+	if (quirks & SDHCI_QUIRK_REG32_RW)
+		host->version = sdhci_readl(host, SDHCI_HOST_VERSION - 2) >> 16;
+	else
+		host->version = sdhci_readw(host, SDHCI_HOST_VERSION);
+
+	add_sdhci(host, max_clk, min_clk);
+	return ret;
+}
diff --git a/include/bitfield.h b/include/bitfield.h
new file mode 100644
index 0000000..ec4815c
--- /dev/null
+++ b/include/bitfield.h
@@ -0,0 +1,58 @@
+/*
+ * Copyright 2013 Broadcom Corporation.
+ *
+ * SPDX-License-Identifier:      GPL-2.0+
+ */
+
+/*
+ * Bitfield operations
+ *
+ * These are generic bitfield operations which allow manipulation of variable
+ * width bitfields within a word. One use of this would be to use data tables
+ * to determine how to reprogram fields within R/W hardware registers.
+ *
+ * Example:
+ *
+ *            old_reg_val
+ * +--------+----+---+--+-----+----------+
+ * |        |    |   |  | old |          |
+ * +--------+----+---+--+-----+----------+
+ *
+ *            new_reg_val
+ * +--------+----+---+--+-----+----------+
+ * |        |    |   |  | new |          |
+ * +--------+----+---+--+-----+----------+
+ *
+ * mask = bitfield_mask(10, 5);
+ * old = bitfield_extract(old_reg_val, 10, 5);
+ * new_reg_val = bitfield_replace(old_reg_val, 10, 5, new);
+ *
+ * The numbers 10 and 5 could for example come from data
+ * tables which describe all bitfields in all registers.
+ */
+
+#include <linux/types.h>
+
+/* Produces a mask of set bits covering a range of a uint value */
+static inline uint bitfield_mask(uint shift, uint width)
+{
+	return ((1 << width) - 1) << shift;
+}
+
+/* Extract the value of a bitfield found within a given register value */
+static inline uint bitfield_extract(uint reg_val, uint shift, uint width)
+{
+	return (reg_val & bitfield_mask(shift, width)) >> shift;
+}
+
+/*
+ * Replace the value of a bitfield found within a given register value
+ * Returns the newly modified uint value with the replaced field.
+ */
+static inline uint bitfield_replace(uint reg_val, uint shift, uint width,
+				    uint bitfield_val)
+{
+	uint mask = bitfield_mask(shift, width);
+
+	return (reg_val & ~mask) | (bitfield_val << shift);
+}
diff --git a/include/configs/bcm28155_ap.h b/include/configs/bcm28155_ap.h
new file mode 100644
index 0000000..8e1c81f
--- /dev/null
+++ b/include/configs/bcm28155_ap.h
@@ -0,0 +1,140 @@
+/*
+ * Copyright 2013 Broadcom Corporation.
+ *
+ * SPDX-License-Identifier:      GPL-2.0+
+ */
+
+#ifndef __BCM28155_AP_H
+#define __BCM28155_AP_H
+
+#include <asm/sizes.h>
+#include <asm/arch/sysmap.h>
+
+/* Architecture, CPU, chip, mach, etc */
+#define CONFIG_ARMV7
+#define CONFIG_KONA
+#define CONFIG_SKIP_LOWLEVEL_INIT
+
+/*
+ * Memory configuration
+ */
+#define CONFIG_SYS_TEXT_BASE		0xae000000
+
+#define CONFIG_SYS_SDRAM_BASE		0x80000000
+#define CONFIG_SYS_SDRAM_SIZE		0x80000000
+#define CONFIG_NR_DRAM_BANKS		1
+
+#define CONFIG_SYS_MALLOC_LEN		SZ_4M	/* see armv7/start.S. */
+#define CONFIG_STACKSIZE		SZ_256K
+
+/* GPIO Driver */
+#define CONFIG_KONA_GPIO
+
+/* MMC/SD Driver */
+#define CONFIG_SDHCI
+#define CONFIG_MMC_SDMA
+#define CONFIG_KONA_SDHCI
+#define CONFIG_MMC
+#define CONFIG_GENERIC_MMC
+
+#define CONFIG_SYS_SDIO_BASE0 SDIO1_BASE_ADDR
+#define CONFIG_SYS_SDIO_BASE1 SDIO2_BASE_ADDR
+#define CONFIG_SYS_SDIO_BASE2 SDIO3_BASE_ADDR
+#define CONFIG_SYS_SDIO_BASE3 SDIO4_BASE_ADDR
+#define CONFIG_SYS_SDIO0_MAX_CLK 48000000
+#define CONFIG_SYS_SDIO1_MAX_CLK 48000000
+#define CONFIG_SYS_SDIO2_MAX_CLK 48000000
+#define CONFIG_SYS_SDIO3_MAX_CLK 48000000
+#define CONFIG_SYS_SDIO0 "sdio1"
+#define CONFIG_SYS_SDIO1 "sdio2"
+#define CONFIG_SYS_SDIO2 "sdio3"
+#define CONFIG_SYS_SDIO3 "sdio4"
+
+/* I2C Driver */
+#define CONFIG_SYS_I2C
+#define CONFIG_SYS_I2C_KONA
+#define CONFIG_SYS_SPD_BUS_NUM	3	/* Start with PMU bus */
+#define CONFIG_SYS_MAX_I2C_BUS	4
+#define CONFIG_SYS_I2C_BASE0	BSC1_BASE_ADDR
+#define CONFIG_SYS_I2C_BASE1	BSC2_BASE_ADDR
+#define CONFIG_SYS_I2C_BASE2	BSC3_BASE_ADDR
+#define CONFIG_SYS_I2C_BASE3	PMU_BSC_BASE_ADDR
+
+/* Timer Driver */
+#define CONFIG_SYS_TIMER_RATE		32000
+#define CONFIG_SYS_TIMER_COUNTER	(TIMER_BASE_ADDR + 4) /* STCLO offset */
+
+/* Init functions */
+#define CONFIG_MISC_INIT_R	/* board's misc_init_r function */
+
+/* Some commands use this as the default load address */
+#define CONFIG_SYS_LOAD_ADDR		CONFIG_SYS_SDRAM_BASE
+
+/* No mtest functions as recommended */
+#undef CONFIG_CMD_MEMORY
+
+/*
+ * This is the initial SP which is used only briefly for relocating the u-boot
+ * image to the top of SDRAM. After relocation u-boot moves the stack to the
+ * proper place.
+ */
+#define CONFIG_SYS_INIT_SP_ADDR		CONFIG_SYS_TEXT_BASE
+
+/* Serial Info */
+#define CONFIG_SYS_NS16550
+#define CONFIG_SYS_NS16550_SERIAL
+/* Post pad 3 bytes after each reg addr */
+#define CONFIG_SYS_NS16550_REG_SIZE	(-4)
+#define CONFIG_SYS_NS16550_CLK		13000000
+#define CONFIG_CONS_INDEX		1
+#define CONFIG_SYS_NS16550_COM1		0x3e000000
+
+#define CONFIG_BAUDRATE			115200
+
+#define CONFIG_ENV_SIZE			0x10000
+#define CONFIG_ENV_IS_NOWHERE
+
+#define CONFIG_SYS_NO_FLASH	/* Not using NAND/NOR unmanaged flash */
+
+/* console configuration */
+#define CONFIG_SYS_CBSIZE		1024	/* Console buffer size */
+#define CONFIG_SYS_PBSIZE		(CONFIG_SYS_CBSIZE + \
+			sizeof(CONFIG_SYS_PROMPT) + 16)	/* Printbuffer size */
+#define CONFIG_SYS_MAXARGS		64
+#define CONFIG_SYS_BARGSIZE		CONFIG_SYS_CBSIZE
+
+/*
+ * One partition type must be defined for part.c
+ * This is necessary for the fatls command to work on an SD card
+ * for example.
+ */
+#define CONFIG_DOS_PARTITION
+
+/* version string, parser, etc */
+#define CONFIG_VERSION_VARIABLE
+#define CONFIG_AUTO_COMPLETE
+#define CONFIG_SYS_HUSH_PARSER
+#define CONFIG_CMDLINE_EDITING
+#define CONFIG_SYS_LONGHELP
+
+#define CONFIG_CRC32_VERIFY
+#define CONFIG_MX_CYCLIC
+
+/* Initial upstream - boot to cmd prompt only */
+#define CONFIG_BOOTCOMMAND		""
+
+/* Commands */
+#include <config_cmd_default.h>
+#define CONFIG_CMD_ASKENV
+#define CONFIG_CMD_CACHE
+#define CONFIG_CMD_FAT
+#define CONFIG_CMD_GPIO
+#define CONFIG_CMD_I2C
+#define CONFIG_CMD_MMC
+#define CONFIG_CMD_BOOTZ
+#define CONFIG_FAT_WRITE
+
+#undef CONFIG_CMD_NET
+#undef CONFIG_CMD_NFS
+
+#endif /* __BCM28155_AP_H */
diff --git a/include/configs/rpi_b.h b/include/configs/rpi_b.h
index 976ceaa..6306d61 100644
--- a/include/configs/rpi_b.h
+++ b/include/configs/rpi_b.h
@@ -95,12 +95,25 @@
 #define CONFIG_SYS_LOAD_ADDR		0x1000000
 #define CONFIG_CONSOLE_MUX
 #define CONFIG_SYS_CONSOLE_IS_IN_ENV
+#define CONFIG_PREBOOT \
+	"if load mmc 0:1 ${loadaddr} /uEnv.txt; then " \
+		"env import -t ${loadaddr} ${filesize}; " \
+	"fi"
+
+#define ENV_DEVICE_SETTINGS \
+	"stdin=serial,lcd\0" \
+	"stdout=serial,lcd\0" \
+	"stderr=serial,lcd\0"
+
 /*
  * Memory layout for where various images get loaded by boot scripts:
  *
  * scriptaddr can be pretty much anywhere that doesn't conflict with something
  *   else. Put it low in memory to avoid conflicts.
  *
+ * pxefile_addr_r can be pretty much anywhere that doesn't conflict with
+ *   something else. Put it low in memory to avoid conflicts.
+ *
  * kernel_addr_r must be within the first 128M of RAM in order for the
  *   kernel's CONFIG_AUTO_ZRELADDR option to work. Since the kernel will
  *   decompress itself to 0x8000 after the start of RAM, kernel_addr_r
@@ -116,68 +129,112 @@
  * ramdisk_addr_r simply shouldn't overlap anything else. Choosing 33M allows
  *   for the FDT/DTB to be up to 1M, which is hopefully plenty.
  */
-#define CONFIG_EXTRA_ENV_SETTINGS \
-	"stdin=serial\0" \
-	"stderr=serial,lcd\0" \
-	"stdout=serial,lcd\0" \
+#define ENV_MEM_LAYOUT_SETTINGS \
 	"scriptaddr=0x00000000\0" \
+	"pxefile_addr_r=0x00100000\0" \
 	"kernel_addr_r=0x01000000\0" \
 	"fdt_addr_r=0x02000000\0" \
 	"fdtfile=bcm2835-rpi-b.dtb\0" \
 	"ramdisk_addr_r=0x02100000\0" \
-	"boot_targets=mmc0\0" \
-	\
-	"script_boot=" \
-		"if fatload ${devtype} ${devnum}:1 " \
-					"${scriptaddr} boot.scr.uimg; then " \
-			"source ${scriptaddr}; " \
-		"fi;\0" \
-	\
+
+#define BOOTCMDS_MMC \
 	"mmc_boot=" \
 		"setenv devtype mmc; " \
 		"if mmc dev ${devnum}; then " \
-			"run script_boot; " \
+			"run scan_boot; " \
 		"fi\0" \
+	"bootcmd_mmc0=setenv devnum 0; run mmc_boot;\0"
+#define BOOT_TARGETS_MMC "mmc0"
+
+#define BOOTCMDS_COMMON \
+	"rootpart=1\0" \
 	\
-	"bootcmd_mmc0=setenv devnum 0; run mmc_boot\0" \
+	"do_script_boot="                                                 \
+		"load ${devtype} ${devnum}:${rootpart} "                  \
+			"${scriptaddr} ${prefix}${script}; "              \
+		"source ${scriptaddr}\0"                                  \
+	\
+	"script_boot="                                                    \
+		"for script in ${boot_scripts}; do "                      \
+			"if test -e ${devtype} ${devnum}:${rootpart} "    \
+					"${prefix}${script}; then "       \
+				"echo Found ${prefix}${script}; "         \
+				"run do_script_boot; "                    \
+				"echo SCRIPT FAILED: continuing...; "     \
+			"fi; "                                            \
+		"done\0"                                                  \
+	\
+	"do_sysboot_boot="                                                \
+		"sysboot ${devtype} ${devnum}:${rootpart} any "           \
+			"${scriptaddr} ${prefix}extlinux/extlinux.conf\0" \
+	\
+	"sysboot_boot="                                                   \
+		"if test -e ${devtype} ${devnum}:${rootpart} "            \
+				"${prefix}extlinux/extlinux.conf; then "  \
+			"echo Found ${prefix}extlinux/extlinux.conf; "    \
+			"run do_sysboot_boot; "                           \
+			"echo SCRIPT FAILED: continuing...; "             \
+		"fi\0"                                                    \
+	\
+	"scan_boot="                                                      \
+		"echo Scanning ${devtype} ${devnum}...; "                 \
+		"for prefix in ${boot_prefixes}; do "                     \
+			"run sysboot_boot; "                              \
+			"run script_boot; "                               \
+		"done\0"                                                  \
+	\
+	"boot_targets=" \
+		BOOT_TARGETS_MMC " " \
+		"\0" \
+	\
+	"boot_prefixes=/\0" \
+	\
+	"boot_scripts=boot.scr.uimg\0" \
+	\
+	BOOTCMDS_MMC
 
 #define CONFIG_BOOTCOMMAND \
 	"for target in ${boot_targets}; do run bootcmd_${target}; done"
 
-#define CONFIG_BOOTDELAY		2
+#define CONFIG_BOOTCOMMAND \
+	"for target in ${boot_targets}; do run bootcmd_${target}; done"
+
+#define CONFIG_EXTRA_ENV_SETTINGS \
+	ENV_DEVICE_SETTINGS \
+	ENV_MEM_LAYOUT_SETTINGS \
+	BOOTCMDS_COMMON
+
+#define CONFIG_BOOTDELAY 2
 
 /* Shell */
-#define CONFIG_SYS_HUSH_PARSER
 #define CONFIG_SYS_MAXARGS		8
 #define CONFIG_SYS_PROMPT		"U-Boot> "
-#define CONFIG_SYS_LONGHELP
-#define CONFIG_CMDLINE_EDITING
 #define CONFIG_COMMAND_HISTORY
-#define CONFIG_AUTO_COMPLETE
 
 /* Commands */
 #include <config_cmd_default.h>
-#define CONFIG_CMD_BOOTZ
 #define CONFIG_CMD_GPIO
 #define CONFIG_CMD_MMC
-#define CONFIG_DOS_PARTITION
 #define CONFIG_PARTITION_UUIDS
 #define CONFIG_CMD_PART
-#define CONFIG_CMD_FS_GENERIC
-#define CONFIG_CMD_FAT
-#define CONFIG_CMD_EXT
-/* Some things don't make sense on this HW or yet */
-#undef CONFIG_CMD_FPGA
-#undef CONFIG_CMD_NET
-#undef CONFIG_CMD_NFS
-#undef CONFIG_CMD_SAVEENV
 
-/* Device tree support for bootm/bootz */
-#define CONFIG_OF_LIBFDT
+/* Device tree support */
 #define CONFIG_OF_BOARD_SETUP
 /* ATAGs support for bootm/bootz */
 #define CONFIG_SETUP_MEMORY_TAGS
 #define CONFIG_CMDLINE_TAG
 #define CONFIG_INITRD_TAG
 
+#include <config_distro_defaults.h>
+
+/* Some things don't make sense on this HW or yet */
+#undef CONFIG_CMD_FPGA
+#undef CONFIG_CMD_NET
+#undef CONFIG_CMD_NFS
+#undef CONFIG_CMD_SAVEENV
+#undef CONFIG_CMD_DHCP
+#undef CONFIG_CMD_MII
+#undef CONFIG_CMD_NET
+#undef CONFIG_CMD_PING
+
 #endif