summaryrefslogtreecommitdiff
path: root/arch/arm/cpu/armv7
diff options
context:
space:
mode:
Diffstat (limited to 'arch/arm/cpu/armv7')
-rw-r--r--arch/arm/cpu/armv7/Makefile1
-rw-r--r--arch/arm/cpu/armv7/am33xx/board.c6
-rw-r--r--arch/arm/cpu/armv7/am33xx/clock_am43xx.c4
-rw-r--r--arch/arm/cpu/armv7/am33xx/clock_ti814x.c5
-rw-r--r--arch/arm/cpu/armv7/am33xx/config.mk6
-rw-r--r--arch/arm/cpu/armv7/am33xx/ddr.c5
-rw-r--r--arch/arm/cpu/armv7/am33xx/emif4.c2
-rw-r--r--arch/arm/cpu/armv7/am33xx/u-boot-spl.lds6
-rw-r--r--arch/arm/cpu/armv7/bcm281xx/Makefile11
-rw-r--r--arch/arm/cpu/armv7/bcm281xx/clk-bcm281xx.c523
-rw-r--r--arch/arm/cpu/armv7/bcm281xx/clk-bsc.c52
-rw-r--r--arch/arm/cpu/armv7/bcm281xx/clk-core.c513
-rw-r--r--arch/arm/cpu/armv7/bcm281xx/clk-core.h495
-rw-r--r--arch/arm/cpu/armv7/bcm281xx/clk-sdio.c73
-rw-r--r--arch/arm/cpu/armv7/bcm281xx/reset.c27
-rw-r--r--arch/arm/cpu/armv7/config.mk17
-rw-r--r--arch/arm/cpu/armv7/exynos/clock.c84
-rw-r--r--arch/arm/cpu/armv7/exynos/pinmux.c7
-rw-r--r--arch/arm/cpu/armv7/kona-common/Makefile9
-rw-r--r--arch/arm/cpu/armv7/kona-common/clk-stubs.c21
-rw-r--r--arch/arm/cpu/armv7/kona-common/hwinit-common.c16
-rw-r--r--arch/arm/cpu/armv7/kona-common/s_init.c12
-rw-r--r--arch/arm/cpu/armv7/omap-common/boot-common.c13
-rw-r--r--arch/arm/cpu/armv7/omap-common/config.mk9
-rw-r--r--arch/arm/cpu/armv7/omap-common/hwinit-common.c3
-rw-r--r--arch/arm/cpu/armv7/omap-common/sata.c3
-rw-r--r--arch/arm/cpu/armv7/omap-common/u-boot-spl.lds6
-rw-r--r--arch/arm/cpu/armv7/omap3/config.mk4
-rw-r--r--arch/arm/cpu/armv7/omap3/lowlevel_init.S3
-rw-r--r--arch/arm/cpu/armv7/omap4/config.mk4
-rw-r--r--arch/arm/cpu/armv7/omap4/hw_data.c18
-rw-r--r--arch/arm/cpu/armv7/omap5/config.mk4
-rw-r--r--arch/arm/cpu/armv7/omap5/prcm-regs.c2
-rw-r--r--arch/arm/cpu/armv7/socfpga/config.mk2
-rw-r--r--arch/arm/cpu/armv7/socfpga/u-boot-spl.lds6
-rw-r--r--arch/arm/cpu/armv7/start.S23
-rw-r--r--arch/arm/cpu/armv7/tegra114/Makefile3
-rw-r--r--arch/arm/cpu/armv7/tegra124/Makefile9
-rw-r--r--arch/arm/cpu/armv7/tegra30/Makefile3
-rw-r--r--arch/arm/cpu/armv7/zynq/Makefile2
-rw-r--r--arch/arm/cpu/armv7/zynq/clk.c664
-rw-r--r--arch/arm/cpu/armv7/zynq/cpu.c14
-rw-r--r--arch/arm/cpu/armv7/zynq/slcr.c17
-rw-r--r--arch/arm/cpu/armv7/zynq/spl.c69
-rw-r--r--arch/arm/cpu/armv7/zynq/timer.c14
-rw-r--r--arch/arm/cpu/armv7/zynq/u-boot-spl.lds61
-rw-r--r--arch/arm/cpu/armv7/zynq/u-boot.lds104
47 files changed, 2799 insertions, 156 deletions
diff --git a/arch/arm/cpu/armv7/Makefile b/arch/arm/cpu/armv7/Makefile
index 0467d00d6a..119ebb3b22 100644
--- a/arch/arm/cpu/armv7/Makefile
+++ b/arch/arm/cpu/armv7/Makefile
@@ -23,6 +23,7 @@ obj-y += nonsec_virt.o
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/am33xx/board.c b/arch/arm/cpu/armv7/am33xx/board.c
index c7dad6681d..2b15a64667 100644
--- a/arch/arm/cpu/armv7/am33xx/board.c
+++ b/arch/arm/cpu/armv7/am33xx/board.c
@@ -36,11 +36,15 @@
DECLARE_GLOBAL_DATA_PTR;
-static const struct gpio_bank gpio_bank_am33xx[4] = {
+static const struct gpio_bank gpio_bank_am33xx[] = {
{ (void *)AM33XX_GPIO0_BASE, METHOD_GPIO_24XX },
{ (void *)AM33XX_GPIO1_BASE, METHOD_GPIO_24XX },
{ (void *)AM33XX_GPIO2_BASE, METHOD_GPIO_24XX },
{ (void *)AM33XX_GPIO3_BASE, METHOD_GPIO_24XX },
+#ifdef CONFIG_AM43XX
+ { (void *)AM33XX_GPIO4_BASE, METHOD_GPIO_24XX },
+ { (void *)AM33XX_GPIO5_BASE, METHOD_GPIO_24XX },
+#endif
};
const struct gpio_bank *const omap_gpio_bank = gpio_bank_am33xx;
diff --git a/arch/arm/cpu/armv7/am33xx/clock_am43xx.c b/arch/arm/cpu/armv7/am33xx/clock_am43xx.c
index 97c00b4925..d0bc2340c8 100644
--- a/arch/arm/cpu/armv7/am33xx/clock_am43xx.c
+++ b/arch/arm/cpu/armv7/am33xx/clock_am43xx.c
@@ -94,10 +94,14 @@ void enable_basic_clocks(void)
&cmper->gpio1clkctrl,
&cmper->gpio2clkctrl,
&cmper->gpio3clkctrl,
+ &cmper->gpio4clkctrl,
+ &cmper->gpio5clkctrl,
&cmper->i2c1clkctrl,
+ &cmper->cpgmac0clkctrl,
&cmper->emiffwclkctrl,
&cmper->emifclkctrl,
&cmper->otfaemifclkctrl,
+ &cmper->qspiclkctrl,
0
};
diff --git a/arch/arm/cpu/armv7/am33xx/clock_ti814x.c b/arch/arm/cpu/armv7/am33xx/clock_ti814x.c
index ef14f47ebc..9b5a47b018 100644
--- a/arch/arm/cpu/armv7/am33xx/clock_ti814x.c
+++ b/arch/arm/cpu/armv7/am33xx/clock_ti814x.c
@@ -211,11 +211,8 @@ static u32 pll_dco_freq_sel(u32 clkout_dco)
static u32 pll_sigma_delta_val(u32 clkout_dco)
{
u32 sig_val = 0;
- float frac_div;
- frac_div = (float) clkout_dco / 250;
- frac_div = frac_div + 0.90;
- sig_val = (int)frac_div;
+ sig_val = (clkout_dco + 225) / 250;
sig_val = sig_val << 24;
return sig_val;
diff --git a/arch/arm/cpu/armv7/am33xx/config.mk b/arch/arm/cpu/armv7/am33xx/config.mk
index 8e3668f781..5294d16708 100644
--- a/arch/arm/cpu/armv7/am33xx/config.mk
+++ b/arch/arm/cpu/armv7/am33xx/config.mk
@@ -4,8 +4,8 @@
# SPDX-License-Identifier: GPL-2.0+
#
ifdef CONFIG_SPL_BUILD
-ALL-y += $(OBJTREE)/MLO
-ALL-$(CONFIG_SPL_SPI_SUPPORT) += $(OBJTREE)/MLO.byteswap
+ALL-y += MLO
+ALL-$(CONFIG_SPL_SPI_SUPPORT) += MLO.byteswap
else
-ALL-y += $(obj)u-boot.img
+ALL-y += u-boot.img
endif
diff --git a/arch/arm/cpu/armv7/am33xx/ddr.c b/arch/arm/cpu/armv7/am33xx/ddr.c
index d05e666a74..9a625c4661 100644
--- a/arch/arm/cpu/armv7/am33xx/ddr.c
+++ b/arch/arm/cpu/armv7/am33xx/ddr.c
@@ -80,8 +80,8 @@ static void configure_mr(int nr, u32 cs)
*/
void config_sdram_emif4d5(const struct emif_regs *regs, int nr)
{
- writel(0x0, &emif_reg[nr]->emif_pwr_mgmt_ctrl);
- writel(0x0, &emif_reg[nr]->emif_pwr_mgmt_ctrl_shdw);
+ writel(0xA0, &emif_reg[nr]->emif_pwr_mgmt_ctrl);
+ writel(0xA0, &emif_reg[nr]->emif_pwr_mgmt_ctrl_shdw);
writel(0x1, &emif_reg[nr]->emif_iodft_tlgc);
writel(regs->zq_config, &emif_reg[nr]->emif_zq_config);
@@ -96,6 +96,7 @@ void config_sdram_emif4d5(const struct emif_regs *regs, int nr)
writel(regs->ref_ctrl, &emif_reg[nr]->emif_sdram_ref_ctrl);
writel(regs->sdram_config, &emif_reg[nr]->emif_sdram_config);
+ writel(regs->sdram_config, &cstat->secure_emif_sdram_config);
if (emif_sdram_type() == EMIF_SDRAM_TYPE_LPDDR2) {
configure_mr(nr, 0);
diff --git a/arch/arm/cpu/armv7/am33xx/emif4.c b/arch/arm/cpu/armv7/am33xx/emif4.c
index d28fceb75c..3e39752380 100644
--- a/arch/arm/cpu/armv7/am33xx/emif4.c
+++ b/arch/arm/cpu/armv7/am33xx/emif4.c
@@ -113,7 +113,7 @@ void config_ddr(unsigned int pll, const struct ctrl_ioregs *ioregs,
writel(readl(&cm_device->cm_dll_ctrl) & ~0x1, &cm_device->cm_dll_ctrl);
while ((readl(&cm_device->cm_dll_ctrl) && CM_DLL_READYST) == 0)
;
- writel(0x0, &ddrctrl->ddrioctrl);
+ writel(0x80000000, &ddrctrl->ddrioctrl);
config_io_ctrl(ioregs);
diff --git a/arch/arm/cpu/armv7/am33xx/u-boot-spl.lds b/arch/arm/cpu/armv7/am33xx/u-boot-spl.lds
index 9302856a95..b1c28c9442 100644
--- a/arch/arm/cpu/armv7/am33xx/u-boot-spl.lds
+++ b/arch/arm/cpu/armv7/am33xx/u-boot-spl.lds
@@ -38,7 +38,11 @@ SECTIONS
. = ALIGN(4);
__image_copy_end = .;
- _end = .;
+
+ .end :
+ {
+ *(.__end)
+ } >.sram
.bss :
{
diff --git a/arch/arm/cpu/armv7/bcm281xx/Makefile b/arch/arm/cpu/armv7/bcm281xx/Makefile
new file mode 100644
index 0000000000..98f5aa59ca
--- /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 0000000000..bc8a170b40
--- /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 0000000000..ba55d0aeb1
--- /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 0000000000..d4425835a1
--- /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 0000000000..882a297797
--- /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 0000000000..49badcbaa7
--- /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 0000000000..3beb0ed9c7
--- /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/config.mk b/arch/arm/cpu/armv7/config.mk
index 38b7c401f8..6c82c3b537 100644
--- a/arch/arm/cpu/armv7/config.mk
+++ b/arch/arm/cpu/armv7/config.mk
@@ -10,16 +10,9 @@
PF_CPPFLAGS_ARMV7 := $(call cc-option, -march=armv7-a, -march=armv5)
PLATFORM_CPPFLAGS += $(PF_CPPFLAGS_ARMV7)
-# SEE README.arm-unaligned-accesses
+# On supported platforms we set the bit which causes us to trap on unaligned
+# memory access. This is the opposite of what the compiler expects to be
+# the default so we must pass in -mno-unaligned-access so that it is aware
+# of our decision.
PF_NO_UNALIGNED := $(call cc-option, -mno-unaligned-access,)
-PLATFORM_NO_UNALIGNED := $(PF_NO_UNALIGNED)
-
-ifneq ($(CONFIG_IMX_CONFIG),)
-ifdef CONFIG_SPL
-ifdef CONFIG_SPL_BUILD
-ALL-y += $(OBJTREE)/SPL
-endif
-else
-ALL-y += $(obj)u-boot.imx
-endif
-endif
+PLATFORM_CPPFLAGS += $(PF_NO_UNALIGNED)
diff --git a/arch/arm/cpu/armv7/exynos/clock.c b/arch/arm/cpu/armv7/exynos/clock.c
index 5bde9d180b..1fea4d6663 100644
--- a/arch/arm/cpu/armv7/exynos/clock.c
+++ b/arch/arm/cpu/armv7/exynos/clock.c
@@ -26,7 +26,7 @@ struct clk_bit_info {
};
/* src_bit div_bit prediv_bit */
-static struct clk_bit_info clk_bit_info[PERIPH_ID_COUNT] = {
+static struct clk_bit_info clk_bit_info[] = {
{0, 0, -1},
{4, 4, -1},
{8, 8, -1},
@@ -870,7 +870,6 @@ static void exynos4_set_mmc_clk(int dev_index, unsigned int div)
struct exynos4_clock *clk =
(struct exynos4_clock *)samsung_get_base_clock();
unsigned int addr;
- unsigned int val;
/*
* CLK_DIV_FSYS1
@@ -890,10 +889,8 @@ static void exynos4_set_mmc_clk(int dev_index, unsigned int div)
dev_index -= 2;
}
- val = readl(addr);
- val &= ~(0xff << ((dev_index << 4) + 8));
- val |= (div & 0xff) << ((dev_index << 4) + 8);
- writel(val, addr);
+ clrsetbits_le32(addr, 0xff << ((dev_index << 4) + 8),
+ (div & 0xff) << ((dev_index << 4) + 8));
}
/* exynos4x12: set the mmc clock */
@@ -902,7 +899,6 @@ static void exynos4x12_set_mmc_clk(int dev_index, unsigned int div)
struct exynos4x12_clock *clk =
(struct exynos4x12_clock *)samsung_get_base_clock();
unsigned int addr;
- unsigned int val;
/*
* CLK_DIV_FSYS1
@@ -917,10 +913,8 @@ static void exynos4x12_set_mmc_clk(int dev_index, unsigned int div)
dev_index -= 2;
}
- val = readl(addr);
- val &= ~(0xff << ((dev_index << 4) + 8));
- val |= (div & 0xff) << ((dev_index << 4) + 8);
- writel(val, addr);
+ clrsetbits_le32(addr, 0xff << ((dev_index << 4) + 8),
+ (div & 0xff) << ((dev_index << 4) + 8));
}
/* exynos5: set the mmc clock */
@@ -929,7 +923,6 @@ static void exynos5_set_mmc_clk(int dev_index, unsigned int div)
struct exynos5_clock *clk =
(struct exynos5_clock *)samsung_get_base_clock();
unsigned int addr;
- unsigned int val;
/*
* CLK_DIV_FSYS1
@@ -944,10 +937,8 @@ static void exynos5_set_mmc_clk(int dev_index, unsigned int div)
dev_index -= 2;
}
- val = readl(addr);
- val &= ~(0xff << ((dev_index << 4) + 8));
- val |= (div & 0xff) << ((dev_index << 4) + 8);
- writel(val, addr);
+ clrsetbits_le32(addr, 0xff << ((dev_index << 4) + 8),
+ (div & 0xff) << ((dev_index << 4) + 8));
}
/* exynos5: set the mmc clock */
@@ -956,7 +947,7 @@ static void exynos5420_set_mmc_clk(int dev_index, unsigned int div)
struct exynos5420_clock *clk =
(struct exynos5420_clock *)samsung_get_base_clock();
unsigned int addr;
- unsigned int val, shift;
+ unsigned int shift;
/*
* CLK_DIV_FSYS1
@@ -967,10 +958,7 @@ static void exynos5420_set_mmc_clk(int dev_index, unsigned int div)
addr = (unsigned int)&clk->div_fsys1;
shift = dev_index * 10;
- val = readl(addr);
- val &= ~(0x3ff << shift);
- val |= (div & 0x3ff) << shift;
- writel(val, addr);
+ clrsetbits_le32(addr, 0x3ff << shift, (div & 0x3ff) << shift);
}
/* get_lcd_clk: return lcd clock frequency */
@@ -1061,7 +1049,6 @@ void exynos4_set_lcd_clk(void)
{
struct exynos4_clock *clk =
(struct exynos4_clock *)samsung_get_base_clock();
- unsigned int cfg = 0;
/*
* CLK_GATE_BLOCK
@@ -1073,9 +1060,7 @@ void exynos4_set_lcd_clk(void)
* CLK_LCD1 [5]
* CLK_GPS [7]
*/
- cfg = readl(&clk->gate_block);
- cfg |= 1 << 4;
- writel(cfg, &clk->gate_block);
+ setbits_le32(&clk->gate_block, 1 << 4);
/*
* CLK_SRC_LCD0
@@ -1085,10 +1070,7 @@ void exynos4_set_lcd_clk(void)
* MIPI0_SEL [12:15]
* set lcd0 src clock 0x6: SCLK_MPLL
*/
- cfg = readl(&clk->src_lcd0);
- cfg &= ~(0xf);
- cfg |= 0x6;
- writel(cfg, &clk->src_lcd0);
+ clrsetbits_le32(&clk->src_lcd0, 0xf, 0x6);
/*
* CLK_GATE_IP_LCD0
@@ -1100,9 +1082,7 @@ void exynos4_set_lcd_clk(void)
* CLK_PPMULCD0 [5]
* Gating all clocks for FIMD0
*/
- cfg = readl(&clk->gate_ip_lcd0);
- cfg |= 1 << 0;
- writel(cfg, &clk->gate_ip_lcd0);
+ setbits_le32(&clk->gate_ip_lcd0, 1 << 0);
/*
* CLK_DIV_LCD0
@@ -1114,16 +1094,13 @@ void exynos4_set_lcd_clk(void)
* MIPI0_PRE_RATIO [23:20]
* set fimd ratio
*/
- cfg &= ~(0xf);
- cfg |= 0x1;
- writel(cfg, &clk->div_lcd0);
+ clrsetbits_le32(&clk->div_lcd0, 0xf, 0x1);
}
void exynos5_set_lcd_clk(void)
{
struct exynos5_clock *clk =
(struct exynos5_clock *)samsung_get_base_clock();
- unsigned int cfg = 0;
/*
* CLK_GATE_BLOCK
@@ -1135,9 +1112,7 @@ void exynos5_set_lcd_clk(void)
* CLK_LCD1 [5]
* CLK_GPS [7]
*/
- cfg = readl(&clk->gate_block);
- cfg |= 1 << 4;
- writel(cfg, &clk->gate_block);
+ setbits_le32(&clk->gate_block, 1 << 4);
/*
* CLK_SRC_LCD0
@@ -1147,10 +1122,7 @@ void exynos5_set_lcd_clk(void)
* MIPI0_SEL [12:15]
* set lcd0 src clock 0x6: SCLK_MPLL
*/
- cfg = readl(&clk->src_disp1_0);
- cfg &= ~(0xf);
- cfg |= 0x6;
- writel(cfg, &clk->src_disp1_0);
+ clrsetbits_le32(&clk->src_disp1_0, 0xf, 0x6);
/*
* CLK_GATE_IP_LCD0
@@ -1162,9 +1134,7 @@ void exynos5_set_lcd_clk(void)
* CLK_PPMULCD0 [5]
* Gating all clocks for FIMD0
*/
- cfg = readl(&clk->gate_ip_disp1);
- cfg |= 1 << 0;
- writel(cfg, &clk->gate_ip_disp1);
+ setbits_le32(&clk->gate_ip_disp1, 1 << 0);
/*
* CLK_DIV_LCD0
@@ -1176,16 +1146,13 @@ void exynos5_set_lcd_clk(void)
* MIPI0_PRE_RATIO [23:20]
* set fimd ratio
*/
- cfg &= ~(0xf);
- cfg |= 0x0;
- writel(cfg, &clk->div_disp1_0);
+ clrsetbits_le32(&clk->div_disp1_0, 0xf, 0x0);
}
void exynos4_set_mipi_clk(void)
{
struct exynos4_clock *clk =
(struct exynos4_clock *)samsung_get_base_clock();
- unsigned int cfg = 0;
/*
* CLK_SRC_LCD0
@@ -1195,10 +1162,7 @@ void exynos4_set_mipi_clk(void)
* MIPI0_SEL [12:15]
* set mipi0 src clock 0x6: SCLK_MPLL
*/
- cfg = readl(&clk->src_lcd0);
- cfg &= ~(0xf << 12);
- cfg |= (0x6 << 12);
- writel(cfg, &clk->src_lcd0);
+ clrsetbits_le32(&clk->src_lcd0, 0xf << 12, 0x6 << 12);
/*
* CLK_SRC_MASK_LCD0
@@ -1208,9 +1172,7 @@ void exynos4_set_mipi_clk(void)
* MIPI0_MASK [12]
* set src mask mipi0 0x1: Unmask
*/
- cfg = readl(&clk->src_mask_lcd0);
- cfg |= (0x1 << 12);
- writel(cfg, &clk->src_mask_lcd0);
+ setbits_le32(&clk->src_mask_lcd0, 0x1 << 12);
/*
* CLK_GATE_IP_LCD0
@@ -1222,9 +1184,7 @@ void exynos4_set_mipi_clk(void)
* CLK_PPMULCD0 [5]
* Gating all clocks for MIPI0
*/
- cfg = readl(&clk->gate_ip_lcd0);
- cfg |= 1 << 3;
- writel(cfg, &clk->gate_ip_lcd0);
+ setbits_le32(&clk->gate_ip_lcd0, 1 << 3);
/*
* CLK_DIV_LCD0
@@ -1236,9 +1196,7 @@ void exynos4_set_mipi_clk(void)
* MIPI0_PRE_RATIO [23:20]
* set mipi ratio
*/
- cfg &= ~(0xf << 16);
- cfg |= (0x1 << 16);
- writel(cfg, &clk->div_lcd0);
+ clrsetbits_le32(&clk->div_lcd0, 0xf << 16, 0x1 << 16);
}
/*
diff --git a/arch/arm/cpu/armv7/exynos/pinmux.c b/arch/arm/cpu/armv7/exynos/pinmux.c
index 904177a149..645c497370 100644
--- a/arch/arm/cpu/armv7/exynos/pinmux.c
+++ b/arch/arm/cpu/armv7/exynos/pinmux.c
@@ -751,12 +751,7 @@ static int exynos5_pinmux_decode_periph_id(const void *blob, int node)
if (err)
return PERIPH_ID_NONE;
- /* check for invalid peripheral id */
- if ((PERIPH_ID_SDMMC4 > cell[1]) || (cell[1] < PERIPH_ID_UART0))
- return cell[1];
-
- debug(" invalid peripheral id\n");
- return PERIPH_ID_NONE;
+ return cell[1];
}
int pinmux_decode_periph_id(const void *blob, int node)
diff --git a/arch/arm/cpu/armv7/kona-common/Makefile b/arch/arm/cpu/armv7/kona-common/Makefile
new file mode 100644
index 0000000000..da225cb4f7
--- /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 0000000000..338e0e4962
--- /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 0000000000..f8b1e063cd
--- /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 0000000000..6066a73c54
--- /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/cpu/armv7/omap-common/boot-common.c b/arch/arm/cpu/armv7/omap-common/boot-common.c
index 69fff323d3..52e0f4a6cf 100644
--- a/arch/arm/cpu/armv7/omap-common/boot-common.c
+++ b/arch/arm/cpu/armv7/omap-common/boot-common.c
@@ -66,7 +66,18 @@ u32 spl_boot_device(void)
u32 spl_boot_mode(void)
{
- return gd->arch.omap_boot_params.omap_bootmode;
+ u32 val = gd->arch.omap_boot_params.omap_bootmode;
+
+ if (val == MMCSD_MODE_RAW)
+ return MMCSD_MODE_RAW;
+ else if (val == MMCSD_MODE_FAT)
+ return MMCSD_MODE_FAT;
+ else
+#ifdef CONFIG_SUPPORT_EMMC_BOOT
+ return MMCSD_MODE_EMMCBOOT;
+#else
+ return MMCSD_MODE_UNDEFINED;
+#endif
}
void spl_board_init(void)
diff --git a/arch/arm/cpu/armv7/omap-common/config.mk b/arch/arm/cpu/armv7/omap-common/config.mk
deleted file mode 100644
index 3a36ab65e1..0000000000
--- a/arch/arm/cpu/armv7/omap-common/config.mk
+++ /dev/null
@@ -1,9 +0,0 @@
-#
-# (C) Copyright 2002
-# Gary Jennejohn, DENX Software Engineering, <garyj@denx.de>
-#
-# SPDX-License-Identifier: GPL-2.0+
-#
-
-# Make ARMv5 to allow more compilers to work, even though its v7a.
-PLATFORM_CPPFLAGS += -march=armv5
diff --git a/arch/arm/cpu/armv7/omap-common/hwinit-common.c b/arch/arm/cpu/armv7/omap-common/hwinit-common.c
index bf2951031d..ade744e31f 100644
--- a/arch/arm/cpu/armv7/omap-common/hwinit-common.c
+++ b/arch/arm/cpu/armv7/omap-common/hwinit-common.c
@@ -248,6 +248,7 @@ u32 get_device_type(void)
(DEVICE_TYPE_MASK)) >> DEVICE_TYPE_SHIFT;
}
+#if defined(CONFIG_DISPLAY_CPUINFO)
/*
* Print CPU information
*/
@@ -258,6 +259,8 @@ int print_cpuinfo(void)
return 0;
}
+#endif
+
#ifndef CONFIG_SYS_DCACHE_OFF
void enable_caches(void)
{
diff --git a/arch/arm/cpu/armv7/omap-common/sata.c b/arch/arm/cpu/armv7/omap-common/sata.c
index f5468c4c97..cad4feed00 100644
--- a/arch/arm/cpu/armv7/omap-common/sata.c
+++ b/arch/arm/cpu/armv7/omap-common/sata.c
@@ -12,6 +12,7 @@
#include <scsi.h>
#include <asm/arch/clock.h>
#include <asm/arch/sata.h>
+#include <sata.h>
#include <asm/io.h>
#include "pipe3-phy.h"
@@ -31,7 +32,7 @@ struct omap_pipe3 sata_phy = {
.dpll_map = dpll_map_sata,
};
-int omap_sata_init(void)
+int init_sata(int dev)
{
int ret;
u32 val;
diff --git a/arch/arm/cpu/armv7/omap-common/u-boot-spl.lds b/arch/arm/cpu/armv7/omap-common/u-boot-spl.lds
index 02aa129733..745603d0fe 100644
--- a/arch/arm/cpu/armv7/omap-common/u-boot-spl.lds
+++ b/arch/arm/cpu/armv7/omap-common/u-boot-spl.lds
@@ -39,7 +39,11 @@ SECTIONS
. = ALIGN(4);
__image_copy_end = .;
- _end = .;
+
+ .end :
+ {
+ *(.__end)
+ }
.bss :
{
diff --git a/arch/arm/cpu/armv7/omap3/config.mk b/arch/arm/cpu/armv7/omap3/config.mk
index 1d6a57c66c..ad44d63840 100644
--- a/arch/arm/cpu/armv7/omap3/config.mk
+++ b/arch/arm/cpu/armv7/omap3/config.mk
@@ -9,7 +9,7 @@
# SPDX-License-Identifier: GPL-2.0+
#
ifdef CONFIG_SPL_BUILD
-ALL-y += $(OBJTREE)/MLO
+ALL-y += MLO
else
-ALL-y += $(obj)u-boot.img
+ALL-y += u-boot.img
endif
diff --git a/arch/arm/cpu/armv7/omap3/lowlevel_init.S b/arch/arm/cpu/armv7/omap3/lowlevel_init.S
index 6f7261b7b8..78577b1d1c 100644
--- a/arch/arm/cpu/armv7/omap3/lowlevel_init.S
+++ b/arch/arm/cpu/armv7/omap3/lowlevel_init.S
@@ -17,9 +17,6 @@
#include <asm/arch/clocks_omap3.h>
#include <linux/linkage.h>
-_TEXT_BASE:
- .word CONFIG_SYS_TEXT_BASE /* sdram load addr from config.mk */
-
#ifdef CONFIG_SPL_BUILD
ENTRY(save_boot_params)
ldr r4, =omap3_boot_device
diff --git a/arch/arm/cpu/armv7/omap4/config.mk b/arch/arm/cpu/armv7/omap4/config.mk
index 1d6a57c66c..ad44d63840 100644
--- a/arch/arm/cpu/armv7/omap4/config.mk
+++ b/arch/arm/cpu/armv7/omap4/config.mk
@@ -9,7 +9,7 @@
# SPDX-License-Identifier: GPL-2.0+
#
ifdef CONFIG_SPL_BUILD
-ALL-y += $(OBJTREE)/MLO
+ALL-y += MLO
else
-ALL-y += $(obj)u-boot.img
+ALL-y += u-boot.img
endif
diff --git a/arch/arm/cpu/armv7/omap4/hw_data.c b/arch/arm/cpu/armv7/omap4/hw_data.c
index 4dec73e9ec..029533c851 100644
--- a/arch/arm/cpu/armv7/omap4/hw_data.c
+++ b/arch/arm/cpu/armv7/omap4/hw_data.c
@@ -172,6 +172,20 @@ struct dplls omap4430_dplls_es1 = {
.ddr = NULL
};
+struct dplls omap4430_dplls_es20 = {
+ .mpu = mpu_dpll_params_1200mhz,
+ .core = core_dpll_params_es2_1600mhz_ddr200mhz,
+ .per = per_dpll_params_1536mhz,
+ .iva = iva_dpll_params_1862mhz,
+#ifdef CONFIG_SYS_OMAP_ABE_SYSCK
+ .abe = abe_dpll_params_sysclk_196608khz,
+#else
+ .abe = &abe_dpll_params_32k_196608khz,
+#endif
+ .usb = usb_dpll_params_1920mhz,
+ .ddr = NULL
+};
+
struct dplls omap4430_dplls = {
.mpu = mpu_dpll_params_1200mhz,
.core = core_dpll_params_1600mhz,
@@ -413,6 +427,10 @@ void hw_data_init(void)
break;
case OMAP4430_ES2_0:
+ *dplls_data = &omap4430_dplls_es20;
+ *omap_vcores = &omap4430_volts;
+ break;
+
case OMAP4430_ES2_1:
case OMAP4430_ES2_2:
case OMAP4430_ES2_3:
diff --git a/arch/arm/cpu/armv7/omap5/config.mk b/arch/arm/cpu/armv7/omap5/config.mk
index 2673af9668..ef2725affa 100644
--- a/arch/arm/cpu/armv7/omap5/config.mk
+++ b/arch/arm/cpu/armv7/omap5/config.mk
@@ -7,7 +7,7 @@
#
ifdef CONFIG_SPL_BUILD
-ALL-y += $(OBJTREE)/MLO
+ALL-y += MLO
else
-ALL-y += $(obj)u-boot.img
+ALL-y += u-boot.img
endif
diff --git a/arch/arm/cpu/armv7/omap5/prcm-regs.c b/arch/arm/cpu/armv7/omap5/prcm-regs.c
index ff328070f7..7292161f3c 100644
--- a/arch/arm/cpu/armv7/omap5/prcm-regs.c
+++ b/arch/arm/cpu/armv7/omap5/prcm-regs.c
@@ -432,7 +432,7 @@ struct omap_sys_ctrl_regs const dra7xx_ctrl = {
.control_srcomp_code_latch = 0x4A002E84,
.control_ddr_control_ext_0 = 0x4A002E88,
.control_padconf_core_base = 0x4A003400,
- .control_std_fuse_opp_vdd_mpu_2 = 0x4A003B24,
+ .control_std_fuse_opp_vdd_mpu_2 = 0x4A003B20,
.control_port_emif1_sdram_config = 0x4AE0C110,
.control_port_emif1_lpddr2_nvm_config = 0x4AE0C114,
.control_port_emif2_sdram_config = 0x4AE0C118,
diff --git a/arch/arm/cpu/armv7/socfpga/config.mk b/arch/arm/cpu/armv7/socfpga/config.mk
index d33ab7d62f..3d18491577 100644
--- a/arch/arm/cpu/armv7/socfpga/config.mk
+++ b/arch/arm/cpu/armv7/socfpga/config.mk
@@ -4,5 +4,5 @@
# SPDX-License-Identifier: GPL-2.0+
#
ifndef CONFIG_SPL_BUILD
-ALL-y += $(obj)u-boot.img
+ALL-y += u-boot.img
endif
diff --git a/arch/arm/cpu/armv7/socfpga/u-boot-spl.lds b/arch/arm/cpu/armv7/socfpga/u-boot-spl.lds
index a7c9c9d281..4282beb395 100644
--- a/arch/arm/cpu/armv7/socfpga/u-boot-spl.lds
+++ b/arch/arm/cpu/armv7/socfpga/u-boot-spl.lds
@@ -28,7 +28,11 @@ SECTIONS
. = ALIGN(4);
__image_copy_end = .;
- _end = .;
+
+ .end :
+ {
+ *(.__end)
+ }
.bss : {
. = ALIGN(4);
diff --git a/arch/arm/cpu/armv7/start.S b/arch/arm/cpu/armv7/start.S
index 5aac773644..ac1e55a708 100644
--- a/arch/arm/cpu/armv7/start.S
+++ b/arch/arm/cpu/armv7/start.S
@@ -70,29 +70,6 @@ _end_vect:
*
*************************************************************************/
-.globl _TEXT_BASE
-_TEXT_BASE:
-#if defined(CONFIG_SPL_BUILD) && defined(CONFIG_SPL_TEXT_BASE)
- .word CONFIG_SPL_TEXT_BASE
-#else
- .word CONFIG_SYS_TEXT_BASE
-#endif
-
-/*
- * These are defined in the board-specific linker script.
- */
-.globl _bss_start_ofs
-_bss_start_ofs:
- .word __bss_start - _start
-
-.globl _bss_end_ofs
-_bss_end_ofs:
- .word __bss_end - _start
-
-.globl _end_ofs
-_end_ofs:
- .word _end - _start
-
#ifdef CONFIG_USE_IRQ
/* IRQ stack memory (calculated at run-time) */
.globl IRQ_STACK_START
diff --git a/arch/arm/cpu/armv7/tegra114/Makefile b/arch/arm/cpu/armv7/tegra114/Makefile
index 886b5092d6..77e231959b 100644
--- a/arch/arm/cpu/armv7/tegra114/Makefile
+++ b/arch/arm/cpu/armv7/tegra114/Makefile
@@ -17,4 +17,5 @@
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
-obj- :=
+# necessary to create built-in.o
+obj- := __dummy__.o
diff --git a/arch/arm/cpu/armv7/tegra124/Makefile b/arch/arm/cpu/armv7/tegra124/Makefile
new file mode 100644
index 0000000000..9478d447db
--- /dev/null
+++ b/arch/arm/cpu/armv7/tegra124/Makefile
@@ -0,0 +1,9 @@
+#
+# (C) Copyright 2013-2014
+# NVIDIA Corporation <www.nvidia.com>
+#
+# SPDX-License-Identifier: GPL-2.0+
+#
+
+# necessary to create built-in.o
+obj- := __dummy__.o
diff --git a/arch/arm/cpu/armv7/tegra30/Makefile b/arch/arm/cpu/armv7/tegra30/Makefile
index 518d6d1b3e..413eba102a 100644
--- a/arch/arm/cpu/armv7/tegra30/Makefile
+++ b/arch/arm/cpu/armv7/tegra30/Makefile
@@ -17,4 +17,5 @@
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
-obj- :=
+# necessary to create built-in.o
+obj- := __dummy__.o
diff --git a/arch/arm/cpu/armv7/zynq/Makefile b/arch/arm/cpu/armv7/zynq/Makefile
index d382d49eb0..3363a3c71b 100644
--- a/arch/arm/cpu/armv7/zynq/Makefile
+++ b/arch/arm/cpu/armv7/zynq/Makefile
@@ -12,3 +12,5 @@ obj-y := timer.o
obj-y += cpu.o
obj-y += ddrc.o
obj-y += slcr.o
+obj-y += clk.o
+obj-$(CONFIG_SPL_BUILD) += spl.o
diff --git a/arch/arm/cpu/armv7/zynq/clk.c b/arch/arm/cpu/armv7/zynq/clk.c
new file mode 100644
index 0000000000..d2885dc2b9
--- /dev/null
+++ b/arch/arm/cpu/armv7/zynq/clk.c
@@ -0,0 +1,664 @@
+/*
+ * Copyright (C) 2013 Soren Brinkmann <soren.brinkmann@xilinx.com>
+ * Copyright (C) 2013 Xilinx, Inc. All rights reserved.
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+#include <common.h>
+#include <errno.h>
+#include <clk.h>
+#include <asm/io.h>
+#include <asm/arch/hardware.h>
+#include <asm/arch/clk.h>
+
+/* Board oscillator frequency */
+#ifndef CONFIG_ZYNQ_PS_CLK_FREQ
+# define CONFIG_ZYNQ_PS_CLK_FREQ 33333333UL
+#endif
+
+/* Register bitfield defines */
+#define PLLCTRL_FBDIV_MASK 0x7f000
+#define PLLCTRL_FBDIV_SHIFT 12
+#define PLLCTRL_BPFORCE_MASK (1 << 4)
+#define PLLCTRL_PWRDWN_MASK 2
+#define PLLCTRL_PWRDWN_SHIFT 1
+#define PLLCTRL_RESET_MASK 1
+#define PLLCTRL_RESET_SHIFT 0
+
+#define ZYNQ_CLK_MAXDIV 0x3f
+#define CLK_CTRL_DIV1_SHIFT 20
+#define CLK_CTRL_DIV1_MASK (ZYNQ_CLK_MAXDIV << CLK_CTRL_DIV1_SHIFT)
+#define CLK_CTRL_DIV0_SHIFT 8
+#define CLK_CTRL_DIV0_MASK (ZYNQ_CLK_MAXDIV << CLK_CTRL_DIV0_SHIFT)
+#define CLK_CTRL_SRCSEL_SHIFT 4
+#define CLK_CTRL_SRCSEL_MASK (0x3 << CLK_CTRL_SRCSEL_SHIFT)
+
+#define CLK_CTRL_DIV2X_SHIFT 26
+#define CLK_CTRL_DIV2X_MASK (ZYNQ_CLK_MAXDIV << CLK_CTRL_DIV2X_SHIFT)
+#define CLK_CTRL_DIV3X_SHIFT 20
+#define CLK_CTRL_DIV3X_MASK (ZYNQ_CLK_MAXDIV << CLK_CTRL_DIV3X_SHIFT)
+
+#define ZYNQ_CLKMUX_SEL_0 0
+#define ZYNQ_CLKMUX_SEL_1 1
+#define ZYNQ_CLKMUX_SEL_2 2
+#define ZYNQ_CLKMUX_SEL_3 3
+
+DECLARE_GLOBAL_DATA_PTR;
+
+struct clk;
+
+/**
+ * struct clk_ops:
+ * @set_rate: Function pointer to set_rate() implementation
+ * @get_rate: Function pointer to get_rate() implementation
+ */
+struct clk_ops {
+ int (*set_rate)(struct clk *clk, unsigned long rate);
+ unsigned long (*get_rate)(struct clk *clk);
+};
+
+/**
+ * struct clk:
+ * @name: Clock name
+ * @frequency: Currenct frequency
+ * @parent: Parent clock
+ * @flags: Clock flags
+ * @reg: Clock control register
+ * @ops: Clock operations
+ */
+struct clk {
+ char *name;
+ unsigned long frequency;
+ enum zynq_clk parent;
+ unsigned int flags;
+ u32 *reg;
+ struct clk_ops ops;
+};
+#define ZYNQ_CLK_FLAGS_HAS_2_DIVS 1
+
+static struct clk clks[clk_max];
+
+/**
+ * __zynq_clk_cpu_get_parent() - Decode clock multiplexer
+ * @srcsel: Mux select value
+ * Returns the clock identifier associated with the selected mux input.
+ */
+static int __zynq_clk_cpu_get_parent(unsigned int srcsel)
+{
+ unsigned int ret;
+
+ switch (srcsel) {
+ case ZYNQ_CLKMUX_SEL_0:
+ case ZYNQ_CLKMUX_SEL_1:
+ ret = armpll_clk;
+ break;
+ case ZYNQ_CLKMUX_SEL_2:
+ ret = ddrpll_clk;
+ break;
+ case ZYNQ_CLKMUX_SEL_3:
+ ret = iopll_clk;
+ break;
+ default:
+ ret = armpll_clk;
+ break;
+ }
+
+ return ret;
+}
+
+/**
+ * ddr2x_get_rate() - Get clock rate of DDR2x clock
+ * @clk: Clock handle
+ * Returns the current clock rate of @clk.
+ */
+static unsigned long ddr2x_get_rate(struct clk *clk)
+{
+ u32 clk_ctrl = readl(clk->reg);
+ u32 div = (clk_ctrl & CLK_CTRL_DIV2X_MASK) >> CLK_CTRL_DIV2X_SHIFT;
+
+ return DIV_ROUND_CLOSEST(zynq_clk_get_rate(clk->parent), div);
+}
+
+/**
+ * ddr3x_get_rate() - Get clock rate of DDR3x clock
+ * @clk: Clock handle
+ * Returns the current clock rate of @clk.
+ */
+static unsigned long ddr3x_get_rate(struct clk *clk)
+{
+ u32 clk_ctrl = readl(clk->reg);
+ u32 div = (clk_ctrl & CLK_CTRL_DIV3X_MASK) >> CLK_CTRL_DIV3X_SHIFT;
+
+ return DIV_ROUND_CLOSEST(zynq_clk_get_rate(clk->parent), div);
+}
+
+static void init_ddr_clocks(void)
+{
+ u32 div0, div1;
+ unsigned long prate = zynq_clk_get_rate(ddrpll_clk);
+ u32 clk_ctrl = readl(&slcr_base->ddr_clk_ctrl);
+
+ /* DDR2x */
+ clks[ddr2x_clk].reg = &slcr_base->ddr_clk_ctrl;
+ clks[ddr2x_clk].parent = ddrpll_clk;
+ clks[ddr2x_clk].name = "ddr_2x";
+ clks[ddr2x_clk].frequency = ddr2x_get_rate(&clks[ddr2x_clk]);
+ clks[ddr2x_clk].ops.get_rate = ddr2x_get_rate;
+
+ /* DDR3x */
+ clks[ddr3x_clk].reg = &slcr_base->ddr_clk_ctrl;
+ clks[ddr3x_clk].parent = ddrpll_clk;
+ clks[ddr3x_clk].name = "ddr_3x";
+ clks[ddr3x_clk].frequency = ddr3x_get_rate(&clks[ddr3x_clk]);
+ clks[ddr3x_clk].ops.get_rate = ddr3x_get_rate;
+
+ /* DCI */
+ clk_ctrl = readl(&slcr_base->dci_clk_ctrl);
+ div0 = (clk_ctrl & CLK_CTRL_DIV0_MASK) >> CLK_CTRL_DIV0_SHIFT;
+ div1 = (clk_ctrl & CLK_CTRL_DIV1_MASK) >> CLK_CTRL_DIV1_SHIFT;
+ clks[dci_clk].reg = &slcr_base->dci_clk_ctrl;
+ clks[dci_clk].parent = ddrpll_clk;
+ clks[dci_clk].frequency = DIV_ROUND_CLOSEST(
+ DIV_ROUND_CLOSEST(prate, div0), div1);
+ clks[dci_clk].name = "dci";
+
+ gd->bd->bi_ddr_freq = clks[ddr3x_clk].frequency / 1000000;
+}
+
+static void init_cpu_clocks(void)
+{
+ int clk_621;
+ u32 reg, div, srcsel;
+ enum zynq_clk parent;
+
+ reg = readl(&slcr_base->arm_clk_ctrl);
+ clk_621 = readl(&slcr_base->clk_621_true) & 1;
+ div = (reg & CLK_CTRL_DIV0_MASK) >> CLK_CTRL_DIV0_SHIFT;
+ srcsel = (reg & CLK_CTRL_SRCSEL_MASK) >> CLK_CTRL_SRCSEL_SHIFT;
+ parent = __zynq_clk_cpu_get_parent(srcsel);
+
+ /* cpu clocks */
+ clks[cpu_6or4x_clk].reg = &slcr_base->arm_clk_ctrl;
+ clks[cpu_6or4x_clk].parent = parent;
+ clks[cpu_6or4x_clk].frequency = DIV_ROUND_CLOSEST(
+ zynq_clk_get_rate(parent), div);
+ clks[cpu_6or4x_clk].name = "cpu_6or4x";
+
+ clks[cpu_3or2x_clk].reg = &slcr_base->arm_clk_ctrl;
+ clks[cpu_3or2x_clk].parent = cpu_6or4x_clk;
+ clks[cpu_3or2x_clk].frequency = zynq_clk_get_rate(cpu_6or4x_clk) / 2;
+ clks[cpu_3or2x_clk].name = "cpu_3or2x";
+
+ clks[cpu_2x_clk].reg = &slcr_base->arm_clk_ctrl;
+ clks[cpu_2x_clk].parent = cpu_6or4x_clk;
+ clks[cpu_2x_clk].frequency = zynq_clk_get_rate(cpu_6or4x_clk) /
+ (2 + clk_621);
+ clks[cpu_2x_clk].name = "cpu_2x";
+
+ clks[cpu_1x_clk].reg = &slcr_base->arm_clk_ctrl;
+ clks[cpu_1x_clk].parent = cpu_6or4x_clk;
+ clks[cpu_1x_clk].frequency = zynq_clk_get_rate(cpu_6or4x_clk) /
+ (4 + 2 * clk_621);
+ clks[cpu_1x_clk].name = "cpu_1x";
+}
+
+/**
+ * periph_calc_two_divs() - Calculate clock dividers
+ * @cur_rate: Current clock rate
+ * @tgt_rate: Target clock rate
+ * @prate: Parent clock rate
+ * @div0: First divider (output)
+ * @div1: Second divider (output)
+ * Returns the actual clock rate possible.
+ *
+ * Calculates clock dividers for clocks with two 6-bit dividers.
+ */
+static unsigned long periph_calc_two_divs(unsigned long cur_rate,
+ unsigned long tgt_rate, unsigned long prate, u32 *div0,
+ u32 *div1)
+{
+ long err, best_err = (long)(~0UL >> 1);
+ unsigned long rate, best_rate = 0;
+ u32 d0, d1;
+
+ for (d0 = 1; d0 <= ZYNQ_CLK_MAXDIV; d0++) {
+ for (d1 = 1; d1 <= ZYNQ_CLK_MAXDIV >> 1; d1++) {
+ rate = DIV_ROUND_CLOSEST(DIV_ROUND_CLOSEST(prate, d0),
+ d1);
+ err = abs(rate - tgt_rate);
+
+ if (err < best_err) {
+ *div0 = d0;
+ *div1 = d1;
+ best_err = err;
+ best_rate = rate;
+ }
+ }
+ }
+
+ return best_rate;
+}
+
+/**
+ * zynq_clk_periph_set_rate() - Set clock rate
+ * @clk: Handle of the peripheral clock
+ * @rate: New clock rate
+ * Sets the clock frequency of @clk to @rate. Returns zero on success.
+ */
+static int zynq_clk_periph_set_rate(struct clk *clk,
+ unsigned long rate)
+{
+ u32 ctrl, div0 = 0, div1 = 0;
+ unsigned long prate, new_rate, cur_rate = clk->frequency;
+
+ ctrl = readl(clk->reg);
+ prate = zynq_clk_get_rate(clk->parent);
+ ctrl &= ~CLK_CTRL_DIV0_MASK;
+
+ if (clk->flags & ZYNQ_CLK_FLAGS_HAS_2_DIVS) {
+ ctrl &= ~CLK_CTRL_DIV1_MASK;
+ new_rate = periph_calc_two_divs(cur_rate, rate, prate, &div0,
+ &div1);
+ ctrl |= div1 << CLK_CTRL_DIV1_SHIFT;
+ } else {
+ div0 = DIV_ROUND_CLOSEST(prate, rate);
+ div0 &= ZYNQ_CLK_MAXDIV;
+ new_rate = DIV_ROUND_CLOSEST(rate, div0);
+ }
+
+ /* write new divs to hardware */
+ ctrl |= div0 << CLK_CTRL_DIV0_SHIFT;
+ writel(ctrl, clk->reg);
+
+ /* update frequency in clk framework */
+ clk->frequency = new_rate;
+
+ return 0;
+}
+
+/**
+ * zynq_clk_periph_get_rate() - Get clock rate
+ * @clk: Handle of the peripheral clock
+ * Returns the current clock rate of @clk.
+ */
+static unsigned long zynq_clk_periph_get_rate(struct clk *clk)
+{
+ u32 clk_ctrl = readl(clk->reg);
+ u32 div0 = (clk_ctrl & CLK_CTRL_DIV0_MASK) >> CLK_CTRL_DIV0_SHIFT;
+ u32 div1 = 1;
+
+ if (clk->flags & ZYNQ_CLK_FLAGS_HAS_2_DIVS)
+ div1 = (clk_ctrl & CLK_CTRL_DIV1_MASK) >> CLK_CTRL_DIV1_SHIFT;
+
+ /* a register value of zero == division by 1 */
+ if (!div0)
+ div0 = 1;
+ if (!div1)
+ div1 = 1;
+
+ return
+ DIV_ROUND_CLOSEST(
+ DIV_ROUND_CLOSEST(zynq_clk_get_rate(clk->parent), div0),
+ div1);
+}
+
+/**
+ * __zynq_clk_periph_get_parent() - Decode clock multiplexer
+ * @srcsel: Mux select value
+ * Returns the clock identifier associated with the selected mux input.
+ */
+static enum zynq_clk __zynq_clk_periph_get_parent(u32 srcsel)
+{
+ switch (srcsel) {
+ case ZYNQ_CLKMUX_SEL_0:
+ case ZYNQ_CLKMUX_SEL_1:
+ return iopll_clk;
+ case ZYNQ_CLKMUX_SEL_2:
+ return armpll_clk;
+ case ZYNQ_CLKMUX_SEL_3:
+ return ddrpll_clk;
+ default:
+ return 0;
+ }
+}
+
+/**
+ * zynq_clk_periph_get_parent() - Decode clock multiplexer
+ * @clk: Clock handle
+ * Returns the clock identifier associated with the selected mux input.
+ */
+static enum zynq_clk zynq_clk_periph_get_parent(struct clk *clk)
+{
+ u32 clk_ctrl = readl(clk->reg);
+ u32 srcsel = (clk_ctrl & CLK_CTRL_SRCSEL_MASK) >> CLK_CTRL_SRCSEL_SHIFT;
+
+ return __zynq_clk_periph_get_parent(srcsel);
+}
+
+/**
+ * zynq_clk_register_periph_clk() - Set up a peripheral clock with the framework
+ * @clk: Pointer to struct clk for the clock
+ * @ctrl: Clock control register
+ * @name: PLL name
+ * @two_divs: Indicates whether the clock features one or two dividers
+ */
+static int zynq_clk_register_periph_clk(struct clk *clk, u32 *ctrl, char *name,
+ bool two_divs)
+{
+ clk->name = name;
+ clk->reg = ctrl;
+ if (two_divs)
+ clk->flags = ZYNQ_CLK_FLAGS_HAS_2_DIVS;
+ clk->parent = zynq_clk_periph_get_parent(clk);
+ clk->frequency = zynq_clk_periph_get_rate(clk);
+ clk->ops.get_rate = zynq_clk_periph_get_rate;
+ clk->ops.set_rate = zynq_clk_periph_set_rate;
+
+ return 0;
+}
+
+static void init_periph_clocks(void)
+{
+ zynq_clk_register_periph_clk(&clks[gem0_clk], &slcr_base->gem0_clk_ctrl,
+ "gem0", 1);
+ zynq_clk_register_periph_clk(&clks[gem1_clk], &slcr_base->gem1_clk_ctrl,
+ "gem1", 1);
+
+ zynq_clk_register_periph_clk(&clks[smc_clk], &slcr_base->smc_clk_ctrl,
+ "smc", 0);
+
+ zynq_clk_register_periph_clk(&clks[lqspi_clk],
+ &slcr_base->lqspi_clk_ctrl, "lqspi", 0);
+
+ zynq_clk_register_periph_clk(&clks[sdio0_clk],
+ &slcr_base->sdio_clk_ctrl, "sdio0", 0);
+ zynq_clk_register_periph_clk(&clks[sdio1_clk],
+ &slcr_base->sdio_clk_ctrl, "sdio1", 0);
+
+ zynq_clk_register_periph_clk(&clks[spi0_clk], &slcr_base->spi_clk_ctrl,
+ "spi0", 0);
+ zynq_clk_register_periph_clk(&clks[spi1_clk], &slcr_base->spi_clk_ctrl,
+ "spi1", 0);
+
+ zynq_clk_register_periph_clk(&clks[uart0_clk],
+ &slcr_base->uart_clk_ctrl, "uart0", 0);
+ zynq_clk_register_periph_clk(&clks[uart1_clk],
+ &slcr_base->uart_clk_ctrl, "uart1", 0);
+
+ zynq_clk_register_periph_clk(&clks[dbg_trc_clk],
+ &slcr_base->dbg_clk_ctrl, "dbg_trc", 0);
+ zynq_clk_register_periph_clk(&clks[dbg_apb_clk],
+ &slcr_base->dbg_clk_ctrl, "dbg_apb", 0);
+
+ zynq_clk_register_periph_clk(&clks[pcap_clk],
+ &slcr_base->pcap_clk_ctrl, "pcap", 0);
+
+ zynq_clk_register_periph_clk(&clks[fclk0_clk],
+ &slcr_base->fpga0_clk_ctrl, "fclk0", 1);
+ zynq_clk_register_periph_clk(&clks[fclk1_clk],
+ &slcr_base->fpga1_clk_ctrl, "fclk1", 1);
+ zynq_clk_register_periph_clk(&clks[fclk2_clk],
+ &slcr_base->fpga2_clk_ctrl, "fclk2", 1);
+ zynq_clk_register_periph_clk(&clks[fclk3_clk],
+ &slcr_base->fpga3_clk_ctrl, "fclk3", 1);
+}
+
+/**
+ * zynq_clk_register_aper_clk() - Set up a APER clock with the framework
+ * @clk: Pointer to struct clk for the clock
+ * @ctrl: Clock control register
+ * @name: PLL name
+ */
+static void zynq_clk_register_aper_clk(struct clk *clk, u32 *ctrl, char *name)
+{
+ clk->name = name;
+ clk->reg = ctrl;
+ clk->parent = cpu_1x_clk;
+ clk->frequency = zynq_clk_get_rate(clk->parent);
+}
+
+static void init_aper_clocks(void)
+{
+ zynq_clk_register_aper_clk(&clks[usb0_aper_clk],
+ &slcr_base->aper_clk_ctrl, "usb0_aper");
+ zynq_clk_register_aper_clk(&clks[usb1_aper_clk],
+ &slcr_base->aper_clk_ctrl, "usb1_aper");
+
+ zynq_clk_register_aper_clk(&clks[gem0_aper_clk],
+ &slcr_base->aper_clk_ctrl, "gem0_aper");
+ zynq_clk_register_aper_clk(&clks[gem1_aper_clk],
+ &slcr_base->aper_clk_ctrl, "gem1_aper");
+
+ zynq_clk_register_aper_clk(&clks[sdio0_aper_clk],
+ &slcr_base->aper_clk_ctrl, "sdio0_aper");
+ zynq_clk_register_aper_clk(&clks[sdio1_aper_clk],
+ &slcr_base->aper_clk_ctrl, "sdio1_aper");
+
+ zynq_clk_register_aper_clk(&clks[spi0_aper_clk],
+ &slcr_base->aper_clk_ctrl, "spi0_aper");
+ zynq_clk_register_aper_clk(&clks[spi1_aper_clk],
+ &slcr_base->aper_clk_ctrl, "spi1_aper");
+
+ zynq_clk_register_aper_clk(&clks[can0_aper_clk],
+ &slcr_base->aper_clk_ctrl, "can0_aper");
+ zynq_clk_register_aper_clk(&clks[can1_aper_clk],
+ &slcr_base->aper_clk_ctrl, "can1_aper");
+
+ zynq_clk_register_aper_clk(&clks[i2c0_aper_clk],
+ &slcr_base->aper_clk_ctrl, "i2c0_aper");
+ zynq_clk_register_aper_clk(&clks[i2c1_aper_clk],
+ &slcr_base->aper_clk_ctrl, "i2c1_aper");
+
+ zynq_clk_register_aper_clk(&clks[uart0_aper_clk],
+ &slcr_base->aper_clk_ctrl, "uart0_aper");
+ zynq_clk_register_aper_clk(&clks[uart1_aper_clk],
+ &slcr_base->aper_clk_ctrl, "uart1_aper");
+
+ zynq_clk_register_aper_clk(&clks[gpio_aper_clk],
+ &slcr_base->aper_clk_ctrl, "gpio_aper");
+
+ zynq_clk_register_aper_clk(&clks[lqspi_aper_clk],
+ &slcr_base->aper_clk_ctrl, "lqspi_aper");
+
+ zynq_clk_register_aper_clk(&clks[smc_aper_clk],
+ &slcr_base->aper_clk_ctrl, "smc_aper");
+}
+
+/**
+ * __zynq_clk_pll_get_rate() - Get PLL rate
+ * @addr: Address of the PLL's control register
+ * Returns the current PLL output rate.
+ */
+static unsigned long __zynq_clk_pll_get_rate(u32 *addr)
+{
+ u32 reg, mul, bypass;
+
+ reg = readl(addr);
+ bypass = reg & PLLCTRL_BPFORCE_MASK;
+ if (bypass)
+ mul = 1;
+ else
+ mul = (reg & PLLCTRL_FBDIV_MASK) >> PLLCTRL_FBDIV_SHIFT;
+
+ return CONFIG_ZYNQ_PS_CLK_FREQ * mul;
+}
+
+/**
+ * zynq_clk_pll_get_rate() - Get PLL rate
+ * @pll: Handle of the PLL
+ * Returns the current clock rate of @pll.
+ */
+static unsigned long zynq_clk_pll_get_rate(struct clk *pll)
+{
+ return __zynq_clk_pll_get_rate(pll->reg);
+}
+
+/**
+ * zynq_clk_register_pll() - Set up a PLL with the framework
+ * @clk: Pointer to struct clk for the PLL
+ * @ctrl: PLL control register
+ * @name: PLL name
+ * @prate: PLL input clock rate
+ */
+static void zynq_clk_register_pll(struct clk *clk, u32 *ctrl, char *name,
+ unsigned long prate)
+{
+ clk->name = name;
+ clk->reg = ctrl;
+ clk->frequency = zynq_clk_pll_get_rate(clk);
+ clk->ops.get_rate = zynq_clk_pll_get_rate;
+}
+
+/**
+ * clkid_2_register() - Get clock control register
+ * @id: Clock identifier of one of the PLLs
+ * Returns the address of the requested PLL's control register.
+ */
+static u32 *clkid_2_register(enum zynq_clk id)
+{
+ switch (id) {
+ case armpll_clk:
+ return &slcr_base->arm_pll_ctrl;
+ case ddrpll_clk:
+ return &slcr_base->ddr_pll_ctrl;
+ case iopll_clk:
+ return &slcr_base->io_pll_ctrl;
+ default:
+ return &slcr_base->io_pll_ctrl;
+ }
+}
+
+/* API */
+/**
+ * zynq_clk_early_init() - Early init for the clock framework
+ *
+ * This function is called from before relocation and sets up the CPU clock
+ * frequency in the global data struct.
+ */
+void zynq_clk_early_init(void)
+{
+ u32 reg = readl(&slcr_base->arm_clk_ctrl);
+ u32 div = (reg & CLK_CTRL_DIV0_MASK) >> CLK_CTRL_DIV0_SHIFT;
+ u32 srcsel = (reg & CLK_CTRL_SRCSEL_MASK) >> CLK_CTRL_SRCSEL_SHIFT;
+ enum zynq_clk parent = __zynq_clk_cpu_get_parent(srcsel);
+ u32 *pllreg = clkid_2_register(parent);
+ unsigned long prate = __zynq_clk_pll_get_rate(pllreg);
+
+ if (!div)
+ div = 1;
+
+ gd->cpu_clk = DIV_ROUND_CLOSEST(prate, div);
+}
+
+/**
+ * get_uart_clk() - Get UART input frequency
+ * @dev_index: UART ID
+ * Returns UART input clock frequency in Hz.
+ *
+ * Compared to zynq_clk_get_rate() this function is designed to work before
+ * relocation and can be called when the serial UART is set up.
+ */
+unsigned long get_uart_clk(int dev_index)
+{
+ u32 reg = readl(&slcr_base->uart_clk_ctrl);
+ u32 div = (reg & CLK_CTRL_DIV0_MASK) >> CLK_CTRL_DIV0_SHIFT;
+ u32 srcsel = (reg & CLK_CTRL_SRCSEL_MASK) >> CLK_CTRL_SRCSEL_SHIFT;
+ enum zynq_clk parent = __zynq_clk_periph_get_parent(srcsel);
+ u32 *pllreg = clkid_2_register(parent);
+ unsigned long prate = __zynq_clk_pll_get_rate(pllreg);
+
+ if (!div)
+ div = 1;
+
+ return DIV_ROUND_CLOSEST(prate, div);
+}
+
+/**
+ * set_cpu_clk_info() - Initialize clock framework
+ * Always returns zero.
+ *
+ * This function is called from common code after relocation and sets up the
+ * clock framework. The framework must not be used before this function had been
+ * called.
+ */
+int set_cpu_clk_info(void)
+{
+ zynq_clk_register_pll(&clks[armpll_clk], &slcr_base->arm_pll_ctrl,
+ "armpll", CONFIG_ZYNQ_PS_CLK_FREQ);
+ zynq_clk_register_pll(&clks[ddrpll_clk], &slcr_base->ddr_pll_ctrl,
+ "ddrpll", CONFIG_ZYNQ_PS_CLK_FREQ);
+ zynq_clk_register_pll(&clks[iopll_clk], &slcr_base->io_pll_ctrl,
+ "iopll", CONFIG_ZYNQ_PS_CLK_FREQ);
+
+ init_ddr_clocks();
+ init_cpu_clocks();
+ init_periph_clocks();
+ init_aper_clocks();
+
+ gd->bd->bi_arm_freq = gd->cpu_clk / 1000000;
+ gd->bd->bi_dsp_freq = 0;
+
+ return 0;
+}
+
+/**
+ * zynq_clk_get_rate() - Get clock rate
+ * @clk: Clock identifier
+ * Returns the current clock rate of @clk on success or zero for an invalid
+ * clock id.
+ */
+unsigned long zynq_clk_get_rate(enum zynq_clk clk)
+{
+ if (clk < 0 || clk >= clk_max)
+ return 0;
+
+ return clks[clk].frequency;
+}
+
+/**
+ * zynq_clk_set_rate() - Set clock rate
+ * @clk: Clock identifier
+ * @rate: Requested clock rate
+ * Passes on the return value from the clock's set_rate() function or negative
+ * errno.
+ */
+int zynq_clk_set_rate(enum zynq_clk clk, unsigned long rate)
+{
+ if (clk < 0 || clk >= clk_max)
+ return -ENODEV;
+
+ if (clks[clk].ops.set_rate)
+ return clks[clk].ops.set_rate(&clks[clk], rate);
+
+ return -ENXIO;
+}
+
+/**
+ * zynq_clk_get_name() - Get clock name
+ * @clk: Clock identifier
+ * Returns the name of @clk.
+ */
+const char *zynq_clk_get_name(enum zynq_clk clk)
+{
+ return clks[clk].name;
+}
+
+/**
+ * soc_clk_dump() - Print clock frequencies
+ * Returns zero on success
+ *
+ * Implementation for the clk dump command.
+ */
+int soc_clk_dump(void)
+{
+ int i;
+
+ printf("clk\t\tfrequency\n");
+ for (i = 0; i < clk_max; i++) {
+ const char *name = zynq_clk_get_name(i);
+ if (name)
+ printf("%10s%20lu\n", name, zynq_clk_get_rate(i));
+ }
+
+ return 0;
+}
diff --git a/arch/arm/cpu/armv7/zynq/cpu.c b/arch/arm/cpu/armv7/zynq/cpu.c
index 9af340e75e..7626b5c1a3 100644
--- a/arch/arm/cpu/armv7/zynq/cpu.c
+++ b/arch/arm/cpu/armv7/zynq/cpu.c
@@ -6,6 +6,7 @@
*/
#include <common.h>
#include <asm/io.h>
+#include <asm/arch/clk.h>
#include <asm/arch/sys_proto.h>
#include <asm/arch/hardware.h>
@@ -16,7 +17,7 @@ void lowlevel_init(void)
int arch_cpu_init(void)
{
zynq_slcr_unlock();
-
+#ifndef CONFIG_SPL_BUILD
/* Device config APB, unlock the PCAP */
writel(0x757BDF0D, &devcfg_base->unlock);
writel(0xFFFFFFFF, &devcfg_base->rom_shadow);
@@ -34,7 +35,8 @@ int arch_cpu_init(void)
/* Urgent write, ports S2/S3 */
writel(0xC, &slcr_base->ddr_urgent);
#endif
-
+#endif
+ zynq_clk_early_init();
zynq_slcr_lock();
return 0;
@@ -46,3 +48,11 @@ void reset_cpu(ulong addr)
while (1)
;
}
+
+#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/zynq/slcr.c b/arch/arm/cpu/armv7/zynq/slcr.c
index b4c11c324c..d7c1882332 100644
--- a/arch/arm/cpu/armv7/zynq/slcr.c
+++ b/arch/arm/cpu/armv7/zynq/slcr.c
@@ -8,6 +8,7 @@
#include <asm/io.h>
#include <malloc.h>
#include <asm/arch/hardware.h>
+#include <asm/arch/clk.h>
#define SLCR_LOCK_MAGIC 0x767B
#define SLCR_UNLOCK_MAGIC 0xDF0D
@@ -50,8 +51,10 @@ void zynq_slcr_cpu_reset(void)
}
/* Setup clk for network */
-void zynq_slcr_gem_clk_setup(u32 gem_id, u32 rclk, u32 clk)
+void zynq_slcr_gem_clk_setup(u32 gem_id, unsigned long clk_rate)
{
+ int ret;
+
zynq_slcr_unlock();
if (gem_id > 1) {
@@ -59,16 +62,16 @@ void zynq_slcr_gem_clk_setup(u32 gem_id, u32 rclk, u32 clk)
goto out;
}
+ ret = zynq_clk_set_rate(gem0_clk + gem_id, clk_rate);
+ if (ret)
+ goto out;
+
if (gem_id) {
- /* Set divisors for appropriate frequency in GEM_CLK_CTRL */
- writel(clk, &slcr_base->gem1_clk_ctrl);
/* Configure GEM_RCLK_CTRL */
- writel(rclk, &slcr_base->gem1_rclk_ctrl);
+ writel(1, &slcr_base->gem1_rclk_ctrl);
} else {
- /* Set divisors for appropriate frequency in GEM_CLK_CTRL */
- writel(clk, &slcr_base->gem0_clk_ctrl);
/* Configure GEM_RCLK_CTRL */
- writel(rclk, &slcr_base->gem0_rclk_ctrl);
+ writel(1, &slcr_base->gem0_rclk_ctrl);
}
udelay(100000);
out:
diff --git a/arch/arm/cpu/armv7/zynq/spl.c b/arch/arm/cpu/armv7/zynq/spl.c
new file mode 100644
index 0000000000..fcad762c03
--- /dev/null
+++ b/arch/arm/cpu/armv7/zynq/spl.c
@@ -0,0 +1,69 @@
+/*
+ * (C) Copyright 2014 Xilinx, Inc. Michal Simek
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+#include <common.h>
+#include <spl.h>
+
+#include <asm/io.h>
+#include <asm/arch/hardware.h>
+#include <asm/arch/spl.h>
+#include <asm/arch/sys_proto.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+void board_init_f(ulong dummy)
+{
+ ps7_init();
+
+ /* Clear the BSS. */
+ memset(__bss_start, 0, __bss_end - __bss_start);
+
+ /* Set global data pointer. */
+ gd = &gdata;
+
+ preloader_console_init();
+ arch_cpu_init();
+ board_init_r(NULL, 0);
+}
+
+u32 spl_boot_device(void)
+{
+ u32 mode;
+
+ switch ((zynq_slcr_get_boot_mode()) & ZYNQ_BM_MASK) {
+#ifdef CONFIG_SPL_SPI_SUPPORT
+ case ZYNQ_BM_QSPI:
+ puts("qspi boot\n");
+ mode = BOOT_DEVICE_SPI;
+ break;
+#endif
+#ifdef CONFIG_SPL_MMC_SUPPORT
+ case ZYNQ_BM_SD:
+ puts("mmc boot\n");
+ mode = BOOT_DEVICE_MMC1;
+ break;
+#endif
+ default:
+ puts("Unsupported boot mode selected\n");
+ hang();
+ }
+
+ return mode;
+}
+
+#ifdef CONFIG_SPL_MMC_SUPPORT
+u32 spl_boot_mode(void)
+{
+ return MMCSD_MODE_FAT;
+}
+#endif
+
+#ifdef CONFIG_SPL_OS_BOOT
+int spl_start_uboot(void)
+{
+ /* boot linux */
+ return 0;
+}
+#endif
diff --git a/arch/arm/cpu/armv7/zynq/timer.c b/arch/arm/cpu/armv7/zynq/timer.c
index 2be253c2c3..303dbcfcea 100644
--- a/arch/arm/cpu/armv7/zynq/timer.c
+++ b/arch/arm/cpu/armv7/zynq/timer.c
@@ -29,6 +29,7 @@
#include <div64.h>
#include <asm/io.h>
#include <asm/arch/hardware.h>
+#include <asm/arch/clk.h>
DECLARE_GLOBAL_DATA_PTR;
@@ -48,7 +49,6 @@ static struct scu_timer *timer_base =
#define TIMER_LOAD_VAL 0xFFFFFFFF
#define TIMER_PRESCALE 255
-#define TIMER_TICK_HZ (CONFIG_CPU_FREQ_HZ / 2 / TIMER_PRESCALE)
int timer_init(void)
{
@@ -56,6 +56,8 @@ int timer_init(void)
(TIMER_PRESCALE << SCUTIMER_CONTROL_PRESCALER_SHIFT) |
SCUTIMER_CONTROL_ENABLE_MASK;
+ gd->arch.timer_rate_hz = (gd->cpu_clk / 2) / (TIMER_PRESCALE + 1);
+
/* Load the timer counter register */
writel(0xFFFFFFFF, &timer_base->load);
@@ -69,7 +71,7 @@ int timer_init(void)
/* Reset time */
gd->arch.lastinc = readl(&timer_base->counter) /
- (TIMER_TICK_HZ / CONFIG_SYS_HZ);
+ (gd->arch.timer_rate_hz / CONFIG_SYS_HZ);
gd->arch.tbl = 0;
return 0;
@@ -83,14 +85,15 @@ ulong get_timer_masked(void)
{
ulong now;
- now = readl(&timer_base->counter) / (TIMER_TICK_HZ / CONFIG_SYS_HZ);
+ now = readl(&timer_base->counter) /
+ (gd->arch.timer_rate_hz / CONFIG_SYS_HZ);
if (gd->arch.lastinc >= now) {
/* Normal mode */
gd->arch.tbl += gd->arch.lastinc - now;
} else {
/* We have an overflow ... */
- gd->arch.tbl += gd->arch.lastinc + TIMER_LOAD_VAL - now;
+ gd->arch.tbl += gd->arch.lastinc + TIMER_LOAD_VAL - now + 1;
}
gd->arch.lastinc = now;
@@ -107,7 +110,8 @@ void __udelay(unsigned long usec)
if (usec == 0)
return;
- countticks = lldiv(TIMER_TICK_HZ * usec, 1000000);
+ countticks = lldiv(((unsigned long long)gd->arch.timer_rate_hz * usec),
+ 1000000);
/* decrementing timer */
timeend = readl(&timer_base->counter) - countticks;
diff --git a/arch/arm/cpu/armv7/zynq/u-boot-spl.lds b/arch/arm/cpu/armv7/zynq/u-boot-spl.lds
new file mode 100644
index 0000000000..0c4501e5c7
--- /dev/null
+++ b/arch/arm/cpu/armv7/zynq/u-boot-spl.lds
@@ -0,0 +1,61 @@
+/*
+ * Copyright (c) 2014 Xilinx, Inc. Michal Simek
+ * Copyright (c) 2004-2008 Texas Instruments
+ *
+ * (C) Copyright 2002
+ * Gary Jennejohn, DENX Software Engineering, <garyj@denx.de>
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+MEMORY { .sram : ORIGIN = CONFIG_SPL_TEXT_BASE,\
+ LENGTH = CONFIG_SPL_MAX_SIZE }
+MEMORY { .sdram : ORIGIN = CONFIG_SPL_BSS_START_ADDR, \
+ LENGTH = CONFIG_SPL_BSS_MAX_SIZE }
+
+OUTPUT_FORMAT("elf32-littlearm", "elf32-littlearm", "elf32-littlearm")
+OUTPUT_ARCH(arm)
+ENTRY(_start)
+SECTIONS
+{
+ . = ALIGN(4);
+ .text :
+ {
+ __image_copy_start = .;
+ CPUDIR/start.o (.text*)
+ *(.text*)
+ } > .sram
+
+ . = ALIGN(4);
+ .rodata : {
+ *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
+ } > .sram
+
+ . = ALIGN(4);
+ .data : {
+ *(.data*)
+ } > .sram
+
+ . = ALIGN(4);
+
+ . = .;
+
+ __image_copy_end = .;
+
+ _end = .;
+
+ /* Move BSS section to RAM because of FAT */
+ .bss (NOLOAD) : {
+ __bss_start = .;
+ *(.bss*)
+ . = ALIGN(4);
+ __bss_end = .;
+ } > .sdram
+
+ /DISCARD/ : { *(.dynsym) }
+ /DISCARD/ : { *(.dynstr*) }
+ /DISCARD/ : { *(.dynamic*) }
+ /DISCARD/ : { *(.plt*) }
+ /DISCARD/ : { *(.interp*) }
+ /DISCARD/ : { *(.gnu*) }
+}
diff --git a/arch/arm/cpu/armv7/zynq/u-boot.lds b/arch/arm/cpu/armv7/zynq/u-boot.lds
new file mode 100644
index 0000000000..f2a5965988
--- /dev/null
+++ b/arch/arm/cpu/armv7/zynq/u-boot.lds
@@ -0,0 +1,104 @@
+/*
+ * Copyright (c) 2004-2008 Texas Instruments
+ *
+ * (C) Copyright 2002
+ * Gary Jennejohn, DENX Software Engineering, <garyj@denx.de>
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+OUTPUT_FORMAT("elf32-littlearm", "elf32-littlearm", "elf32-littlearm")
+OUTPUT_ARCH(arm)
+ENTRY(_start)
+SECTIONS
+{
+ . = 0x00000000;
+
+ . = ALIGN(4);
+ .text :
+ {
+ *(.__image_copy_start)
+ CPUDIR/start.o (.text*)
+ *(.text*)
+ }
+
+ . = ALIGN(4);
+ .rodata : { *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*))) }
+
+ . = ALIGN(4);
+ .data : {
+ *(.data*)
+ }
+
+ . = ALIGN(4);
+
+ . = .;
+
+ . = ALIGN(4);
+ .u_boot_list : {
+ KEEP(*(SORT(.u_boot_list*)));
+ }
+
+ . = ALIGN(4);
+
+ .image_copy_end :
+ {
+ *(.__image_copy_end)
+ }
+
+ .rel_dyn_start :
+ {
+ *(.__rel_dyn_start)
+ }
+
+ .rel.dyn : {
+ *(.rel*)
+ }
+
+ .rel_dyn_end :
+ {
+ *(.__rel_dyn_end)
+ }
+
+ .end :
+ {
+ *(.__end)
+ }
+
+ _image_binary_end = .;
+
+/*
+ * Compiler-generated __bss_start and __bss_end, see arch/arm/lib/bss.c
+ * __bss_base and __bss_limit are for linker only (overlay ordering)
+ */
+
+ .bss_start __rel_dyn_start (OVERLAY) : {
+ KEEP(*(.__bss_start));
+ __bss_base = .;
+ }
+
+ .bss __bss_base (OVERLAY) : {
+ *(.bss*)
+ . = ALIGN(4);
+ __bss_limit = .;
+ }
+
+ .bss_end __bss_limit (OVERLAY) : {
+ KEEP(*(.__bss_end));
+ }
+
+ /*
+ * Zynq needs to discard more sections because the user
+ * is expected to pass this image on to tools for boot.bin
+ * generation that require them to be dropped.
+ */
+ /DISCARD/ : { *(.dynsym) }
+ /DISCARD/ : { *(.dynbss*) }
+ /DISCARD/ : { *(.dynstr*) }
+ /DISCARD/ : { *(.dynamic*) }
+ /DISCARD/ : { *(.plt*) }
+ /DISCARD/ : { *(.interp*) }
+ /DISCARD/ : { *(.gnu*) }
+ /DISCARD/ : { *(.ARM.exidx*) }
+ /DISCARD/ : { *(.gnu.linkonce.armexidx.*) }
+}