board: arm:: Add support for Broadcom BCM23550
authorSteve Rae <srae@broadcom.com>
Thu, 2 Jun 2016 22:10:56 +0000 (15:10 -0700)
committerTom Rini <trini@konsulko.com>
Mon, 13 Jun 2016 12:56:02 +0000 (08:56 -0400)
Add support for the Broadcom BCM23550 board.

Signed-off-by: Steve Rae <srae@broadcom.com>
20 files changed:
arch/arm/Kconfig
arch/arm/cpu/armv7/Makefile
arch/arm/cpu/armv7/bcm235xx/Makefile [new file with mode: 0644]
arch/arm/cpu/armv7/bcm235xx/clk-bcm235xx.c [new file with mode: 0644]
arch/arm/cpu/armv7/bcm235xx/clk-bsc.c [new file with mode: 0644]
arch/arm/cpu/armv7/bcm235xx/clk-core.c [new file with mode: 0644]
arch/arm/cpu/armv7/bcm235xx/clk-core.h [new file with mode: 0644]
arch/arm/cpu/armv7/bcm235xx/clk-eth.c [new file with mode: 0644]
arch/arm/cpu/armv7/bcm235xx/clk-sdio.c [new file with mode: 0644]
arch/arm/cpu/armv7/bcm235xx/clk-usb-otg.c [new file with mode: 0644]
arch/arm/cpu/armv7/kona-common/Makefile
arch/arm/cpu/armv7/kona-common/reset.S [new file with mode: 0644]
arch/arm/include/asm/arch-bcm235xx/gpio.h [new file with mode: 0644]
arch/arm/include/asm/arch-bcm235xx/sysmap.h [new file with mode: 0644]
board/broadcom/bcm23550_w1d/Kconfig [new file with mode: 0644]
board/broadcom/bcm23550_w1d/MAINTAINERS [new file with mode: 0644]
board/broadcom/bcm23550_w1d/Makefile [new file with mode: 0644]
board/broadcom/bcm23550_w1d/bcm23550_w1d.c [new file with mode: 0644]
configs/bcm23550_w1d_defconfig [new file with mode: 0644]
include/configs/bcm23550_w1d.h [new file with mode: 0644]

index e75c4c0fa6df5a2f9f8a928458d2f290ec6e5205..9f78fb098463dbb90c46934b4c279e7f7b8b47d6 100644 (file)
@@ -441,6 +441,10 @@ config TARGET_TI816X_EVM
        select CPU_V7
        select SUPPORT_SPL
 
+config TARGET_BCM23550_W1D
+       bool "Support bcm23550_w1d"
+       select CPU_V7
+
 config TARGET_BCM28155_AP
        bool "Support bcm28155_ap"
        select CPU_V7
@@ -898,6 +902,7 @@ source "board/armadeus/apf27/Kconfig"
 source "board/armltd/vexpress/Kconfig"
 source "board/armltd/vexpress64/Kconfig"
 source "board/bluegiga/apx4devkit/Kconfig"
+source "board/broadcom/bcm23550_w1d/Kconfig"
 source "board/broadcom/bcm28155_ap/Kconfig"
 source "board/broadcom/bcmcygnus/Kconfig"
 source "board/broadcom/bcmnsp/Kconfig"
index 328c4b10e9768f67724f0ded8b1382f8dbafdcd5..0a5ac97df0d0a7f60ddda86952c75ab7a4e0520e 100644 (file)
@@ -38,6 +38,7 @@ obj-y += s5p-common/
 endif
 
 obj-$(if $(filter am33xx,$(SOC)),y) += am33xx/
+obj-$(if $(filter bcm235xx,$(SOC)),y) += bcm235xx/
 obj-$(if $(filter bcm281xx,$(SOC)),y) += bcm281xx/
 obj-$(if $(filter bcmcygnus,$(SOC)),y) += bcmcygnus/
 obj-$(if $(filter bcmnsp,$(SOC)),y) += bcmnsp/
diff --git a/arch/arm/cpu/armv7/bcm235xx/Makefile b/arch/arm/cpu/armv7/bcm235xx/Makefile
new file mode 100644 (file)
index 0000000..7fdb263
--- /dev/null
@@ -0,0 +1,12 @@
+#
+# Copyright 2013 Broadcom Corporation.
+#
+# SPDX-License-Identifier:     GPL-2.0+
+#
+
+obj-y  += clk-core.o
+obj-y  += clk-bcm235xx.o
+obj-y  += clk-sdio.o
+obj-y  += clk-bsc.o
+obj-$(CONFIG_BCM_SF2_ETH) += clk-eth.o
+obj-y  += clk-usb-otg.o
diff --git a/arch/arm/cpu/armv7/bcm235xx/clk-bcm235xx.c b/arch/arm/cpu/armv7/bcm235xx/clk-bcm235xx.c
new file mode 100644 (file)
index 0000000..ce3d019
--- /dev/null
@@ -0,0 +1,573 @@
+/*
+ * Copyright 2013 Broadcom Corporation.
+ *
+ * SPDX-License-Identifier:    GPL-2.0+
+ */
+
+/*
+ *
+ * bcm235xx-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
+};
+
+unsigned long esub_freq_tbl[8] = {
+       78 * CLOCK_1M,
+       156 * CLOCK_1M,
+       156 * CLOCK_1M,
+       156 * CLOCK_1M,
+       208 * CLOCK_1M,
+       208 * CLOCK_1M,
+       208 * 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 usb_otg_ahb_data = {
+       .gate           = HW_SW_GATE_AUTO(0x0348, 16, 0, 1),
+};
+
+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,
+};
+
+#ifdef CONFIG_BCM_SF2_ETH
+static struct ccu_clock esub_ccu_clk = {
+       .clk = {
+               .name = "esub_ccu_clk",
+               .ops = &ccu_clk_ops,
+               .ccu_clk_mgr_base = ESUB_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 = esub_freq_tbl,
+};
+#endif
+
+/*
+ * Bus clocks
+ */
+
+/* KPM bus clocks */
+static struct bus_clock usb_otg_ahb_clk = {
+       .clk = {
+               .name = "usb_otg_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 = &usb_otg_ahb_data,
+};
+
+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(usb_otg_ahb),
+       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),
+#ifdef CONFIG_BCM_SF2_ETH
+       CLK_LK(esub_ccu),
+#endif
+};
+
+/* public array size */
+unsigned int arch_clk_tbl_array_size = ARRAY_SIZE(arch_clk_tbl);
diff --git a/arch/arm/cpu/armv7/bcm235xx/clk-bsc.c b/arch/arm/cpu/armv7/bcm235xx/clk-bsc.c
new file mode 100644 (file)
index 0000000..d263068
--- /dev/null
@@ -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/bcm235xx/clk-core.c b/arch/arm/cpu/armv7/bcm235xx/clk-core.c
new file mode 100644 (file)
index 0000000..2b5da6b
--- /dev/null
@@ -0,0 +1,513 @@
+/*
+ * Copyright 2013 Broadcom Corporation.
+ *
+ * SPDX-License-Identifier:    GPL-2.0+
+ */
+
+/*
+ *
+ * bcm235xx 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/bcm235xx/clk-core.h b/arch/arm/cpu/armv7/bcm235xx/clk-core.h
new file mode 100644 (file)
index 0000000..de9a1ef
--- /dev/null
@@ -0,0 +1,491 @@
+/*
+ * 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);
+
+/* 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;
+
+int clk_get_and_enable(char *clkstr);
diff --git a/arch/arm/cpu/armv7/bcm235xx/clk-eth.c b/arch/arm/cpu/armv7/bcm235xx/clk-eth.c
new file mode 100644 (file)
index 0000000..b0b92b9
--- /dev/null
@@ -0,0 +1,143 @@
+/*
+ * Copyright 2014 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"
+
+#define WR_ACCESS_ADDR                 ESUB_CLK_BASE_ADDR
+#define WR_ACCESS_PASSWORD                             0xA5A500
+
+#define PLLE_POST_RESETB_ADDR          (ESUB_CLK_BASE_ADDR + 0x00000C00)
+
+#define PLLE_RESETB_ADDR               (ESUB_CLK_BASE_ADDR + 0x00000C58)
+#define PLLE_RESETB_I_PLL_RESETB_PLLE_MASK             0x00010000
+#define PLLE_POST_RESETB_I_POST_RESETB_PLLE_MASK       0x00000001
+
+#define PLL_LOCK_ADDR                  (ESUB_CLK_BASE_ADDR + 0x00000C38)
+#define PLL_LOCK_PLL_LOCK_PLLE_MASK                    0x00000001
+
+#define ESW_SYS_DIV_ADDR               (ESUB_CLK_BASE_ADDR + 0x00000A04)
+#define ESW_SYS_DIV_PLL_SELECT_MASK                    0x00000300
+#define ESW_SYS_DIV_DIV_MASK                           0x0000001C
+#define ESW_SYS_DIV_PLL_VAR_208M_CLK_SELECT            0x00000100
+#define ESW_SYS_DIV_DIV_SELECT                         0x4
+#define ESW_SYS_DIV_TRIGGER_MASK                       0x00000001
+
+#define ESUB_AXI_DIV_DEBUG_ADDR                (ESUB_CLK_BASE_ADDR + 0x00000E04)
+#define ESUB_AXI_DIV_DEBUG_PLL_SELECT_MASK             0x0000001C
+#define ESUB_AXI_DIV_DEBUG_PLL_SELECT_OVERRIDE_MASK    0x00000040
+#define ESUB_AXI_DIV_DEBUG_PLL_VAR_208M_CLK_SELECT     0x0
+#define ESUB_AXI_DIV_DEBUG_TRIGGER_MASK                        0x00000001
+
+#define PLL_MAX_RETRY  100
+
+/* Enable appropriate clocks for Ethernet */
+int clk_eth_enable(void)
+{
+       int rc = -1;
+       int retry_count = 0;
+       rc = clk_get_and_enable("esub_ccu_clk");
+
+       /* Enable Access to CCU registers */
+       writel((1 | WR_ACCESS_PASSWORD), WR_ACCESS_ADDR);
+
+       writel(readl(PLLE_POST_RESETB_ADDR) &
+              ~PLLE_POST_RESETB_I_POST_RESETB_PLLE_MASK,
+              PLLE_POST_RESETB_ADDR);
+
+       /* Take PLL out of reset and put into normal mode */
+       writel(readl(PLLE_RESETB_ADDR) | PLLE_RESETB_I_PLL_RESETB_PLLE_MASK,
+              PLLE_RESETB_ADDR);
+
+       /* Wait for PLL lock */
+       rc = -1;
+       while (retry_count < PLL_MAX_RETRY) {
+               udelay(100);
+               if (readl(PLL_LOCK_ADDR) & PLL_LOCK_PLL_LOCK_PLLE_MASK) {
+                       rc = 0;
+                       break;
+               }
+               retry_count++;
+       }
+
+       if (rc == -1) {
+               printf("%s: ETH-PLL lock timeout, Ethernet is not enabled!\n",
+                      __func__);
+               return -1;
+       }
+
+       writel(readl(PLLE_POST_RESETB_ADDR) |
+              PLLE_POST_RESETB_I_POST_RESETB_PLLE_MASK,
+              PLLE_POST_RESETB_ADDR);
+
+       /* Switch esw_sys_clk to use 104MHz(208MHz/2) clock */
+       writel((readl(ESW_SYS_DIV_ADDR) &
+               ~(ESW_SYS_DIV_PLL_SELECT_MASK | ESW_SYS_DIV_DIV_MASK)) |
+              ESW_SYS_DIV_PLL_VAR_208M_CLK_SELECT | ESW_SYS_DIV_DIV_SELECT,
+              ESW_SYS_DIV_ADDR);
+
+       writel(readl(ESW_SYS_DIV_ADDR) | ESW_SYS_DIV_TRIGGER_MASK,
+              ESW_SYS_DIV_ADDR);
+
+       /* Wait for trigger complete */
+       rc = -1;
+       retry_count = 0;
+       while (retry_count < PLL_MAX_RETRY) {
+               udelay(100);
+               if (!(readl(ESW_SYS_DIV_ADDR) & ESW_SYS_DIV_TRIGGER_MASK)) {
+                       rc = 0;
+                       break;
+               }
+               retry_count++;
+       }
+
+       if (rc == -1) {
+               printf("%s: SYS CLK Trigger timeout, Ethernet is not enabled!\n",
+                      __func__);
+               return -1;
+       }
+
+       /* switch Esub AXI clock to 208MHz */
+       writel((readl(ESUB_AXI_DIV_DEBUG_ADDR) &
+               ~(ESUB_AXI_DIV_DEBUG_PLL_SELECT_MASK |
+                 ESUB_AXI_DIV_DEBUG_PLL_SELECT_OVERRIDE_MASK |
+                 ESUB_AXI_DIV_DEBUG_TRIGGER_MASK)) |
+              ESUB_AXI_DIV_DEBUG_PLL_VAR_208M_CLK_SELECT |
+              ESUB_AXI_DIV_DEBUG_PLL_SELECT_OVERRIDE_MASK,
+              ESUB_AXI_DIV_DEBUG_ADDR);
+
+       writel(readl(ESUB_AXI_DIV_DEBUG_ADDR) |
+              ESUB_AXI_DIV_DEBUG_TRIGGER_MASK,
+              ESUB_AXI_DIV_DEBUG_ADDR);
+
+       /* Wait for trigger complete */
+       rc = -1;
+       retry_count = 0;
+       while (retry_count < PLL_MAX_RETRY) {
+               udelay(100);
+               if (!(readl(ESUB_AXI_DIV_DEBUG_ADDR) &
+                     ESUB_AXI_DIV_DEBUG_TRIGGER_MASK)) {
+                       rc = 0;
+                       break;
+               }
+               retry_count++;
+       }
+
+       if (rc == -1) {
+               printf("%s: AXI CLK Trigger timeout, Ethernet is not enabled!\n",
+                      __func__);
+               return -1;
+       }
+
+       /* Disable Access to CCU registers */
+       writel(WR_ACCESS_PASSWORD, WR_ACCESS_ADDR);
+
+       return rc;
+}
diff --git a/arch/arm/cpu/armv7/bcm235xx/clk-sdio.c b/arch/arm/cpu/armv7/bcm235xx/clk-sdio.c
new file mode 100644 (file)
index 0000000..b2ce6d6
--- /dev/null
@@ -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/bcm235xx/clk-usb-otg.c b/arch/arm/cpu/armv7/bcm235xx/clk-usb-otg.c
new file mode 100644 (file)
index 0000000..1d7c5af
--- /dev/null
@@ -0,0 +1,27 @@
+/*
+ * Copyright 2014 Broadcom Corporation.
+ *
+ * SPDX-License-Identifier:    GPL-2.0+
+ */
+
+#include <common.h>
+#include <asm/errno.h>
+#include <asm/arch/sysmap.h>
+#include "clk-core.h"
+
+/* Enable appropriate clocks for the USB OTG port */
+int clk_usb_otg_enable(void *base)
+{
+       char *ahbstr;
+
+       switch ((u32) base) {
+       case HSOTG_BASE_ADDR:
+               ahbstr = "usb_otg_ahb_clk";
+               break;
+       default:
+               printf("%s: base 0x%p not found\n", __func__, base);
+               return -EINVAL;
+       }
+
+       return clk_get_and_enable(ahbstr);
+}
index da225cb4f744248ca1c43fa92cab82e6b8378373..5167ebbef906176288e0257472b83e44ca00fa77 100644 (file)
@@ -7,3 +7,4 @@
 obj-y  += s_init.o
 obj-y  += hwinit-common.o
 obj-y  += clk-stubs.o
+obj-${CONFIG_KONA_RESET_S} += reset.o
diff --git a/arch/arm/cpu/armv7/kona-common/reset.S b/arch/arm/cpu/armv7/kona-common/reset.S
new file mode 100644 (file)
index 0000000..220a1ec
--- /dev/null
@@ -0,0 +1,26 @@
+/*
+ * Copyright 2013 Broadcom Corporation.
+ *
+ * SPDX-License-Identifier:    GPL-2.0+
+ */
+
+.globl reset_cpu
+reset_cpu:
+       ldr     r1, =0x35001f00
+       ldr     r2, [r1]
+       ldr     r4, =0x80000000
+       and     r4, r2, r4
+       ldr     r3, =0xA5A500
+       orr     r4, r4, r3
+       orr     r4, r4, #0x1
+
+       str     r4, [r1]
+
+       ldr     r1, =0x35001f04
+       ldr     r2, [r1]
+       ldr     r4, =0x80000000
+       and     r4, r2, r4
+       str     r4, [r1]
+
+_loop_forever:
+       b       _loop_forever
diff --git a/arch/arm/include/asm/arch-bcm235xx/gpio.h b/arch/arm/include/asm/arch-bcm235xx/gpio.h
new file mode 100644 (file)
index 0000000..da31f98
--- /dev/null
@@ -0,0 +1,15 @@
+/*
+ * Copyright 2013 Broadcom Corporation.
+ *
+ * SPDX-License-Identifier:    GPL-2.0+
+ */
+
+#ifndef __ARCH_BCM235XX_GPIO_H
+#define __ARCH_BCM235XX_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-bcm235xx/sysmap.h b/arch/arm/include/asm/arch-bcm235xx/sysmap.h
new file mode 100644 (file)
index 0000000..90eb2ff
--- /dev/null
@@ -0,0 +1,31 @@
+/*
+ * Copyright 2013 Broadcom Corporation.
+ *
+ * SPDX-License-Identifier:    GPL-2.0+
+ */
+
+#ifndef __ARCH_BCM235XX_SYSMAP_H
+
+#define BSC1_BASE_ADDR         0x3e016000
+#define BSC2_BASE_ADDR         0x3e017000
+#define BSC3_BASE_ADDR         0x3e018000
+#define GPIO2_BASE_ADDR                0x35003000
+#define HSOTG_BASE_ADDR                0x3f120000
+#define HSOTG_CTRL_BASE_ADDR   0x3f130000
+#define KONA_MST_CLK_BASE_ADDR 0x3f001000
+#define KONA_SLV_CLK_BASE_ADDR 0x3e011000
+#define PMU_BSC_BASE_ADDR      0x3500d000
+#define SDIO1_BASE_ADDR                0x3f180000
+#define SDIO2_BASE_ADDR                0x3f190000
+#define SDIO3_BASE_ADDR                0x3f1a0000
+#define SDIO4_BASE_ADDR                0x3f1b0000
+#define TIMER_BASE_ADDR                0x3e00d000
+
+#define HSOTG_DCTL_OFFSET                                      0x00000804
+#define    HSOTG_DCTL_SFTDISCON_MASK                           0x00000002
+
+#define HSOTG_CTRL_PHY_P1CTL_OFFSET                            0x00000008
+#define    HSOTG_CTRL_PHY_P1CTL_SOFT_RESET_MASK                        0x00000002
+#define    HSOTG_CTRL_PHY_P1CTL_NON_DRIVING_MASK               0x00000001
+
+#endif
diff --git a/board/broadcom/bcm23550_w1d/Kconfig b/board/broadcom/bcm23550_w1d/Kconfig
new file mode 100644 (file)
index 0000000..007a127
--- /dev/null
@@ -0,0 +1,15 @@
+if TARGET_BCM23550_W1D
+
+config SYS_BOARD
+       default "bcm23550_w1d"
+
+config SYS_VENDOR
+       default "broadcom"
+
+config SYS_SOC
+       default "bcm235xx"
+
+config SYS_CONFIG_NAME
+       default "bcm23550_w1d"
+
+endif
diff --git a/board/broadcom/bcm23550_w1d/MAINTAINERS b/board/broadcom/bcm23550_w1d/MAINTAINERS
new file mode 100644 (file)
index 0000000..fdaa539
--- /dev/null
@@ -0,0 +1,6 @@
+BCM23550_W1D BOARD
+M:     Steve Rae <srae@broadcom.com>
+S:     Maintained
+F:     board/broadcom/bcm23550_w1d/
+F:     include/configs/bcm23550_w1d.h
+F:     configs/bcm23550_w1d_defconfig
diff --git a/board/broadcom/bcm23550_w1d/Makefile b/board/broadcom/bcm23550_w1d/Makefile
new file mode 100644 (file)
index 0000000..76bd032
--- /dev/null
@@ -0,0 +1,7 @@
+#
+# Copyright 2013 Broadcom Corporation.
+#
+# SPDX-License-Identifier:     GPL-2.0+
+#
+
+obj-y  += bcm23550_w1d.o
diff --git a/board/broadcom/bcm23550_w1d/bcm23550_w1d.c b/board/broadcom/bcm23550_w1d/bcm23550_w1d.c
new file mode 100644 (file)
index 0000000..0cb059f
--- /dev/null
@@ -0,0 +1,120 @@
+/*
+ * 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>
+
+#include <usb.h>
+#include <usb/dwc2_udc.h>
+#include <g_dnl.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
+
+#ifndef CONFIG_USB_SERIALNO
+#define CONFIG_USB_SERIALNO "1234567890"
+#endif
+
+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)
+{
+       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
+
+#ifdef CONFIG_USB_GADGET
+static struct dwc2_plat_otg_data bcm_otg_data = {
+       .regs_otg       = HSOTG_BASE_ADDR
+};
+
+int board_usb_init(int index, enum usb_init_type init)
+{
+       debug("%s: performing dwc2_udc_probe\n", __func__);
+       return dwc2_udc_probe(&bcm_otg_data);
+}
+
+int g_dnl_bind_fixup(struct usb_device_descriptor *dev, const char *name)
+{
+       debug("%s\n", __func__);
+       if (!getenv("serial#"))
+               g_dnl_set_serialnumber(CONFIG_USB_SERIALNO);
+       return 0;
+}
+
+int g_dnl_get_board_bcd_device_number(int gcnum)
+{
+       debug("%s\n", __func__);
+       return 1;
+}
+
+int board_usb_cleanup(int index, enum usb_init_type init)
+{
+       debug("%s\n", __func__);
+       return 0;
+}
+#endif
diff --git a/configs/bcm23550_w1d_defconfig b/configs/bcm23550_w1d_defconfig
new file mode 100644 (file)
index 0000000..3328e51
--- /dev/null
@@ -0,0 +1,24 @@
+CONFIG_ARM=y
+CONFIG_TARGET_BCM23550_W1D=y
+CONFIG_HUSH_PARSER=y
+CONFIG_CMD_BOOTZ=y
+# CONFIG_CMD_IMLS is not set
+CONFIG_CMD_ASKENV=y
+# CONFIG_CMD_FLASH is not set
+CONFIG_CMD_MMC=y
+CONFIG_CMD_I2C=y
+CONFIG_CMD_GPIO=y
+# CONFIG_CMD_SETEXPR is not set
+# CONFIG_CMD_NET is not set
+# CONFIG_CMD_NFS is not set
+CONFIG_CMD_CACHE=y
+CONFIG_CMD_FAT=y
+CONFIG_SYS_NS16550=y
+CONFIG_USB=y
+CONFIG_USB_GADGET=y
+CONFIG_USB_GADGET_DWC2_OTG=y
+CONFIG_USB_GADGET_DOWNLOAD=y
+CONFIG_G_DNL_MANUFACTURER="Broadcom Corporation"
+CONFIG_G_DNL_VENDOR_NUM=0x18d1
+CONFIG_G_DNL_PRODUCT_NUM=0x0d02
+CONFIG_OF_LIBFDT=y
diff --git a/include/configs/bcm23550_w1d.h b/include/configs/bcm23550_w1d.h
new file mode 100644 (file)
index 0000000..bd3c711
--- /dev/null
@@ -0,0 +1,148 @@
+/*
+ * Copyright 2013 Broadcom Corporation.
+ *
+ * SPDX-License-Identifier:    GPL-2.0+
+ */
+
+#ifndef __BCM23550_W1D_H
+#define __BCM23550_W1D_H
+
+#include <linux/sizes.h>
+#include <asm/arch/sysmap.h>
+
+/* CPU, chip, mach, etc */
+#define CONFIG_KONA
+#define CONFIG_SKIP_LOWLEVEL_INIT
+#define CONFIG_KONA_RESET_S
+
+/*
+ * Memory configuration
+ */
+#define CONFIG_SYS_TEXT_BASE           0x9f000000
+
+#define CONFIG_SYS_SDRAM_BASE          0x80000000
+#define CONFIG_SYS_SDRAM_SIZE          0x20000000
+#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 */
+
+/*
+ * 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_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
+
+/* must fit into GPT:u-boot-env partition */
+#define CONFIG_ENV_IS_IN_MMC
+#define CONFIG_SYS_MMC_ENV_DEV         0
+#define CONFIG_ENV_OFFSET              (0x00011a00 * 512)
+#define CONFIG_ENV_SIZE                        (8 * 512)
+
+#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
+#define CONFIG_EFI_PARTITION
+
+/* version string, parser, etc */
+#define CONFIG_VERSION_VARIABLE
+#define CONFIG_AUTO_COMPLETE
+#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 */
+#define CONFIG_FAT_WRITE
+
+/* Fastboot and USB OTG */
+#define CONFIG_USB_FUNCTION_FASTBOOT
+#define CONFIG_CMD_FASTBOOT
+#define CONFIG_FASTBOOT_FLASH
+#define CONFIG_FASTBOOT_FLASH_MMC_DEV  0
+#define CONFIG_SYS_CACHELINE_SIZE      64
+#define CONFIG_FASTBOOT_BUF_SIZE       0x1d000000
+#define CONFIG_FASTBOOT_BUF_ADDR       CONFIG_SYS_SDRAM_BASE
+#undef CONFIG_USB_GADGET_VBUS_DRAW
+#define CONFIG_USB_GADGET_VBUS_DRAW    0
+#define CONFIG_USB_GADGET_DWC2_PHY_8_BIT
+#define CONFIG_USB_GADGET_BCM_UDC_OTG_PHY
+#define CONFIG_USBID_ADDR              0x34052c46
+
+#define CONFIG_SYS_ICACHE_OFF
+#define CONFIG_SYS_DCACHE_OFF
+#define CONFIG_SYS_L2CACHE_OFF
+
+#endif /* __BCM23550_W1D_H */