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