Add support for the Broadcom BCM23550 board. Signed-off-by: Steve Rae <srae@broadcom.com>master
parent
1e031249a5
commit
43486e4cd0
@ -0,0 +1,12 @@ |
|||||||
|
#
|
||||||
|
# Copyright 2013 Broadcom Corporation.
|
||||||
|
#
|
||||||
|
# SPDX-License-Identifier: GPL-2.0+
|
||||||
|
#
|
||||||
|
|
||||||
|
obj-y += clk-core.o
|
||||||
|
obj-y += clk-bcm235xx.o
|
||||||
|
obj-y += clk-sdio.o
|
||||||
|
obj-y += clk-bsc.o
|
||||||
|
obj-$(CONFIG_BCM_SF2_ETH) += clk-eth.o
|
||||||
|
obj-y += clk-usb-otg.o
|
@ -0,0 +1,573 @@ |
|||||||
|
/*
|
||||||
|
* Copyright 2013 Broadcom Corporation. |
||||||
|
* |
||||||
|
* SPDX-License-Identifier: GPL-2.0+ |
||||||
|
*/ |
||||||
|
|
||||||
|
/*
|
||||||
|
* |
||||||
|
* bcm235xx-specific clock tables |
||||||
|
* |
||||||
|
*/ |
||||||
|
|
||||||
|
#include <common.h> |
||||||
|
#include <asm/io.h> |
||||||
|
#include <asm/errno.h> |
||||||
|
#include <asm/arch/sysmap.h> |
||||||
|
#include <asm/kona-common/clk.h> |
||||||
|
#include "clk-core.h" |
||||||
|
|
||||||
|
#define CLOCK_1K 1000 |
||||||
|
#define CLOCK_1M (CLOCK_1K * 1000) |
||||||
|
|
||||||
|
/* declare a reference clock */ |
||||||
|
#define DECLARE_REF_CLK(clk_name, clk_parent, clk_rate, clk_div) \ |
||||||
|
static struct refclk clk_name = { \
|
||||||
|
.clk = { \
|
||||||
|
.name = #clk_name, \
|
||||||
|
.parent = clk_parent, \
|
||||||
|
.rate = clk_rate, \
|
||||||
|
.div = clk_div, \
|
||||||
|
.ops = &ref_clk_ops, \
|
||||||
|
}, \
|
||||||
|
} |
||||||
|
|
||||||
|
/*
|
||||||
|
* Reference clocks |
||||||
|
*/ |
||||||
|
|
||||||
|
/* Declare a list of reference clocks */ |
||||||
|
DECLARE_REF_CLK(ref_crystal, 0, 26 * CLOCK_1M, 1); |
||||||
|
DECLARE_REF_CLK(var_96m, 0, 96 * CLOCK_1M, 1); |
||||||
|
DECLARE_REF_CLK(ref_96m, 0, 96 * CLOCK_1M, 1); |
||||||
|
DECLARE_REF_CLK(ref_312m, 0, 312 * CLOCK_1M, 0); |
||||||
|
DECLARE_REF_CLK(ref_104m, &ref_312m.clk, 104 * CLOCK_1M, 3); |
||||||
|
DECLARE_REF_CLK(ref_52m, &ref_104m.clk, 52 * CLOCK_1M, 2); |
||||||
|
DECLARE_REF_CLK(ref_13m, &ref_52m.clk, 13 * CLOCK_1M, 4); |
||||||
|
DECLARE_REF_CLK(var_312m, 0, 312 * CLOCK_1M, 0); |
||||||
|
DECLARE_REF_CLK(var_104m, &var_312m.clk, 104 * CLOCK_1M, 3); |
||||||
|
DECLARE_REF_CLK(var_52m, &var_104m.clk, 52 * CLOCK_1M, 2); |
||||||
|
DECLARE_REF_CLK(var_13m, &var_52m.clk, 13 * CLOCK_1M, 4); |
||||||
|
|
||||||
|
struct refclk_lkup { |
||||||
|
struct refclk *procclk; |
||||||
|
const char *name; |
||||||
|
}; |
||||||
|
|
||||||
|
/* Lookup table for string to clk tranlation */ |
||||||
|
#define MKSTR(x) {&x, #x} |
||||||
|
static struct refclk_lkup refclk_str_tbl[] = { |
||||||
|
MKSTR(ref_crystal), MKSTR(var_96m), MKSTR(ref_96m), |
||||||
|
MKSTR(ref_312m), MKSTR(ref_104m), MKSTR(ref_52m), |
||||||
|
MKSTR(ref_13m), MKSTR(var_312m), MKSTR(var_104m), |
||||||
|
MKSTR(var_52m), MKSTR(var_13m), |
||||||
|
}; |
||||||
|
|
||||||
|
int refclk_entries = sizeof(refclk_str_tbl)/sizeof(refclk_str_tbl[0]); |
||||||
|
|
||||||
|
/* convert ref clock string to clock structure pointer */ |
||||||
|
struct refclk *refclk_str_to_clk(const char *name) |
||||||
|
{ |
||||||
|
int i; |
||||||
|
struct refclk_lkup *tblp = refclk_str_tbl; |
||||||
|
for (i = 0; i < refclk_entries; i++, tblp++) { |
||||||
|
if (!(strcmp(name, tblp->name))) |
||||||
|
return tblp->procclk; |
||||||
|
} |
||||||
|
return NULL; |
||||||
|
} |
||||||
|
|
||||||
|
/* frequency tables indexed by freq_id */ |
||||||
|
unsigned long master_axi_freq_tbl[8] = { |
||||||
|
26 * CLOCK_1M, |
||||||
|
52 * CLOCK_1M, |
||||||
|
104 * CLOCK_1M, |
||||||
|
156 * CLOCK_1M, |
||||||
|
156 * CLOCK_1M, |
||||||
|
208 * CLOCK_1M, |
||||||
|
312 * CLOCK_1M, |
||||||
|
312 * CLOCK_1M |
||||||
|
}; |
||||||
|
|
||||||
|
unsigned long master_ahb_freq_tbl[8] = { |
||||||
|
26 * CLOCK_1M, |
||||||
|
52 * CLOCK_1M, |
||||||
|
52 * CLOCK_1M, |
||||||
|
52 * CLOCK_1M, |
||||||
|
78 * CLOCK_1M, |
||||||
|
104 * CLOCK_1M, |
||||||
|
104 * CLOCK_1M, |
||||||
|
156 * CLOCK_1M |
||||||
|
}; |
||||||
|
|
||||||
|
unsigned long slave_axi_freq_tbl[8] = { |
||||||
|
26 * CLOCK_1M, |
||||||
|
52 * CLOCK_1M, |
||||||
|
78 * CLOCK_1M, |
||||||
|
104 * CLOCK_1M, |
||||||
|
156 * CLOCK_1M, |
||||||
|
156 * CLOCK_1M |
||||||
|
}; |
||||||
|
|
||||||
|
unsigned long slave_apb_freq_tbl[8] = { |
||||||
|
26 * CLOCK_1M, |
||||||
|
26 * CLOCK_1M, |
||||||
|
39 * CLOCK_1M, |
||||||
|
52 * CLOCK_1M, |
||||||
|
52 * CLOCK_1M, |
||||||
|
78 * CLOCK_1M |
||||||
|
}; |
||||||
|
|
||||||
|
unsigned long esub_freq_tbl[8] = { |
||||||
|
78 * CLOCK_1M, |
||||||
|
156 * CLOCK_1M, |
||||||
|
156 * CLOCK_1M, |
||||||
|
156 * CLOCK_1M, |
||||||
|
208 * CLOCK_1M, |
||||||
|
208 * CLOCK_1M, |
||||||
|
208 * CLOCK_1M |
||||||
|
}; |
||||||
|
|
||||||
|
static struct bus_clk_data bsc1_apb_data = { |
||||||
|
.gate = HW_SW_GATE_AUTO(0x0458, 16, 0, 1), |
||||||
|
}; |
||||||
|
|
||||||
|
static struct bus_clk_data bsc2_apb_data = { |
||||||
|
.gate = HW_SW_GATE_AUTO(0x045c, 16, 0, 1), |
||||||
|
}; |
||||||
|
|
||||||
|
static struct bus_clk_data bsc3_apb_data = { |
||||||
|
.gate = HW_SW_GATE_AUTO(0x0484, 16, 0, 1), |
||||||
|
}; |
||||||
|
|
||||||
|
/* * Master CCU clocks */ |
||||||
|
static struct peri_clk_data sdio1_data = { |
||||||
|
.gate = HW_SW_GATE(0x0358, 18, 2, 3), |
||||||
|
.clocks = CLOCKS("ref_crystal", |
||||||
|
"var_52m", |
||||||
|
"ref_52m", |
||||||
|
"var_96m", |
||||||
|
"ref_96m"), |
||||||
|
.sel = SELECTOR(0x0a28, 0, 3), |
||||||
|
.div = DIVIDER(0x0a28, 4, 14), |
||||||
|
.trig = TRIGGER(0x0afc, 9), |
||||||
|
}; |
||||||
|
|
||||||
|
static struct peri_clk_data sdio2_data = { |
||||||
|
.gate = HW_SW_GATE(0x035c, 18, 2, 3), |
||||||
|
.clocks = CLOCKS("ref_crystal", |
||||||
|
"var_52m", |
||||||
|
"ref_52m", |
||||||
|
"var_96m", |
||||||
|
"ref_96m"), |
||||||
|
.sel = SELECTOR(0x0a2c, 0, 3), |
||||||
|
.div = DIVIDER(0x0a2c, 4, 14), |
||||||
|
.trig = TRIGGER(0x0afc, 10), |
||||||
|
}; |
||||||
|
|
||||||
|
static struct peri_clk_data sdio3_data = { |
||||||
|
.gate = HW_SW_GATE(0x0364, 18, 2, 3), |
||||||
|
.clocks = CLOCKS("ref_crystal", |
||||||
|
"var_52m", |
||||||
|
"ref_52m", |
||||||
|
"var_96m", |
||||||
|
"ref_96m"), |
||||||
|
.sel = SELECTOR(0x0a34, 0, 3), |
||||||
|
.div = DIVIDER(0x0a34, 4, 14), |
||||||
|
.trig = TRIGGER(0x0afc, 12), |
||||||
|
}; |
||||||
|
|
||||||
|
static struct peri_clk_data sdio4_data = { |
||||||
|
.gate = HW_SW_GATE(0x0360, 18, 2, 3), |
||||||
|
.clocks = CLOCKS("ref_crystal", |
||||||
|
"var_52m", |
||||||
|
"ref_52m", |
||||||
|
"var_96m", |
||||||
|
"ref_96m"), |
||||||
|
.sel = SELECTOR(0x0a30, 0, 3), |
||||||
|
.div = DIVIDER(0x0a30, 4, 14), |
||||||
|
.trig = TRIGGER(0x0afc, 11), |
||||||
|
}; |
||||||
|
|
||||||
|
static struct peri_clk_data sdio1_sleep_data = { |
||||||
|
.clocks = CLOCKS("ref_32k"), |
||||||
|
.gate = SW_ONLY_GATE(0x0358, 20, 4), |
||||||
|
}; |
||||||
|
|
||||||
|
static struct peri_clk_data sdio2_sleep_data = { |
||||||
|
.clocks = CLOCKS("ref_32k"), |
||||||
|
.gate = SW_ONLY_GATE(0x035c, 20, 4), |
||||||
|
}; |
||||||
|
|
||||||
|
static struct peri_clk_data sdio3_sleep_data = { |
||||||
|
.clocks = CLOCKS("ref_32k"), |
||||||
|
.gate = SW_ONLY_GATE(0x0364, 20, 4), |
||||||
|
}; |
||||||
|
|
||||||
|
static struct peri_clk_data sdio4_sleep_data = { |
||||||
|
.clocks = CLOCKS("ref_32k"), |
||||||
|
.gate = SW_ONLY_GATE(0x0360, 20, 4), |
||||||
|
}; |
||||||
|
|
||||||
|
static struct bus_clk_data usb_otg_ahb_data = { |
||||||
|
.gate = HW_SW_GATE_AUTO(0x0348, 16, 0, 1), |
||||||
|
}; |
||||||
|
|
||||||
|
static struct bus_clk_data sdio1_ahb_data = { |
||||||
|
.gate = HW_SW_GATE_AUTO(0x0358, 16, 0, 1), |
||||||
|
}; |
||||||
|
|
||||||
|
static struct bus_clk_data sdio2_ahb_data = { |
||||||
|
.gate = HW_SW_GATE_AUTO(0x035c, 16, 0, 1), |
||||||
|
}; |
||||||
|
|
||||||
|
static struct bus_clk_data sdio3_ahb_data = { |
||||||
|
.gate = HW_SW_GATE_AUTO(0x0364, 16, 0, 1), |
||||||
|
}; |
||||||
|
|
||||||
|
static struct bus_clk_data sdio4_ahb_data = { |
||||||
|
.gate = HW_SW_GATE_AUTO(0x0360, 16, 0, 1), |
||||||
|
}; |
||||||
|
|
||||||
|
/* * Slave CCU clocks */ |
||||||
|
static struct peri_clk_data bsc1_data = { |
||||||
|
.gate = HW_SW_GATE(0x0458, 18, 2, 3), |
||||||
|
.clocks = CLOCKS("ref_crystal", |
||||||
|
"var_104m", |
||||||
|
"ref_104m", |
||||||
|
"var_13m", |
||||||
|
"ref_13m"), |
||||||
|
.sel = SELECTOR(0x0a64, 0, 3), |
||||||
|
.trig = TRIGGER(0x0afc, 23), |
||||||
|
}; |
||||||
|
|
||||||
|
static struct peri_clk_data bsc2_data = { |
||||||
|
.gate = HW_SW_GATE(0x045c, 18, 2, 3), |
||||||
|
.clocks = CLOCKS("ref_crystal", |
||||||
|
"var_104m", |
||||||
|
"ref_104m", |
||||||
|
"var_13m", |
||||||
|
"ref_13m"), |
||||||
|
.sel = SELECTOR(0x0a68, 0, 3), |
||||||
|
.trig = TRIGGER(0x0afc, 24), |
||||||
|
}; |
||||||
|
|
||||||
|
static struct peri_clk_data bsc3_data = { |
||||||
|
.gate = HW_SW_GATE(0x0484, 18, 2, 3), |
||||||
|
.clocks = CLOCKS("ref_crystal", |
||||||
|
"var_104m", |
||||||
|
"ref_104m", |
||||||
|
"var_13m", |
||||||
|
"ref_13m"), |
||||||
|
.sel = SELECTOR(0x0a84, 0, 3), |
||||||
|
.trig = TRIGGER(0x0b00, 2), |
||||||
|
}; |
||||||
|
|
||||||
|
/*
|
||||||
|
* CCU clocks |
||||||
|
*/ |
||||||
|
|
||||||
|
static struct ccu_clock kpm_ccu_clk = { |
||||||
|
.clk = { |
||||||
|
.name = "kpm_ccu_clk", |
||||||
|
.ops = &ccu_clk_ops, |
||||||
|
.ccu_clk_mgr_base = KONA_MST_CLK_BASE_ADDR, |
||||||
|
}, |
||||||
|
.num_policy_masks = 1, |
||||||
|
.policy_freq_offset = 0x00000008, |
||||||
|
.freq_bit_shift = 8, |
||||||
|
.policy_ctl_offset = 0x0000000c, |
||||||
|
.policy0_mask_offset = 0x00000010, |
||||||
|
.policy1_mask_offset = 0x00000014, |
||||||
|
.policy2_mask_offset = 0x00000018, |
||||||
|
.policy3_mask_offset = 0x0000001c, |
||||||
|
.lvm_en_offset = 0x00000034, |
||||||
|
.freq_id = 2, |
||||||
|
.freq_tbl = master_axi_freq_tbl, |
||||||
|
}; |
||||||
|
|
||||||
|
static struct ccu_clock kps_ccu_clk = { |
||||||
|
.clk = { |
||||||
|
.name = "kps_ccu_clk", |
||||||
|
.ops = &ccu_clk_ops, |
||||||
|
.ccu_clk_mgr_base = KONA_SLV_CLK_BASE_ADDR, |
||||||
|
}, |
||||||
|
.num_policy_masks = 2, |
||||||
|
.policy_freq_offset = 0x00000008, |
||||||
|
.freq_bit_shift = 8, |
||||||
|
.policy_ctl_offset = 0x0000000c, |
||||||
|
.policy0_mask_offset = 0x00000010, |
||||||
|
.policy1_mask_offset = 0x00000014, |
||||||
|
.policy2_mask_offset = 0x00000018, |
||||||
|
.policy3_mask_offset = 0x0000001c, |
||||||
|
.policy0_mask2_offset = 0x00000048, |
||||||
|
.policy1_mask2_offset = 0x0000004c, |
||||||
|
.policy2_mask2_offset = 0x00000050, |
||||||
|
.policy3_mask2_offset = 0x00000054, |
||||||
|
.lvm_en_offset = 0x00000034, |
||||||
|
.freq_id = 2, |
||||||
|
.freq_tbl = slave_axi_freq_tbl, |
||||||
|
}; |
||||||
|
|
||||||
|
#ifdef CONFIG_BCM_SF2_ETH |
||||||
|
static struct ccu_clock esub_ccu_clk = { |
||||||
|
.clk = { |
||||||
|
.name = "esub_ccu_clk", |
||||||
|
.ops = &ccu_clk_ops, |
||||||
|
.ccu_clk_mgr_base = ESUB_CLK_BASE_ADDR, |
||||||
|
}, |
||||||
|
.num_policy_masks = 1, |
||||||
|
.policy_freq_offset = 0x00000008, |
||||||
|
.freq_bit_shift = 8, |
||||||
|
.policy_ctl_offset = 0x0000000c, |
||||||
|
.policy0_mask_offset = 0x00000010, |
||||||
|
.policy1_mask_offset = 0x00000014, |
||||||
|
.policy2_mask_offset = 0x00000018, |
||||||
|
.policy3_mask_offset = 0x0000001c, |
||||||
|
.lvm_en_offset = 0x00000034, |
||||||
|
.freq_id = 2, |
||||||
|
.freq_tbl = esub_freq_tbl, |
||||||
|
}; |
||||||
|
#endif |
||||||
|
|
||||||
|
/*
|
||||||
|
* Bus clocks |
||||||
|
*/ |
||||||
|
|
||||||
|
/* KPM bus clocks */ |
||||||
|
static struct bus_clock usb_otg_ahb_clk = { |
||||||
|
.clk = { |
||||||
|
.name = "usb_otg_ahb_clk", |
||||||
|
.parent = &kpm_ccu_clk.clk, |
||||||
|
.ops = &bus_clk_ops, |
||||||
|
.ccu_clk_mgr_base = KONA_MST_CLK_BASE_ADDR, |
||||||
|
}, |
||||||
|
.freq_tbl = master_ahb_freq_tbl, |
||||||
|
.data = &usb_otg_ahb_data, |
||||||
|
}; |
||||||
|
|
||||||
|
static struct bus_clock sdio1_ahb_clk = { |
||||||
|
.clk = { |
||||||
|
.name = "sdio1_ahb_clk", |
||||||
|
.parent = &kpm_ccu_clk.clk, |
||||||
|
.ops = &bus_clk_ops, |
||||||
|
.ccu_clk_mgr_base = KONA_MST_CLK_BASE_ADDR, |
||||||
|
}, |
||||||
|
.freq_tbl = master_ahb_freq_tbl, |
||||||
|
.data = &sdio1_ahb_data, |
||||||
|
}; |
||||||
|
|
||||||
|
static struct bus_clock sdio2_ahb_clk = { |
||||||
|
.clk = { |
||||||
|
.name = "sdio2_ahb_clk", |
||||||
|
.parent = &kpm_ccu_clk.clk, |
||||||
|
.ops = &bus_clk_ops, |
||||||
|
.ccu_clk_mgr_base = KONA_MST_CLK_BASE_ADDR, |
||||||
|
}, |
||||||
|
.freq_tbl = master_ahb_freq_tbl, |
||||||
|
.data = &sdio2_ahb_data, |
||||||
|
}; |
||||||
|
|
||||||
|
static struct bus_clock sdio3_ahb_clk = { |
||||||
|
.clk = { |
||||||
|
.name = "sdio3_ahb_clk", |
||||||
|
.parent = &kpm_ccu_clk.clk, |
||||||
|
.ops = &bus_clk_ops, |
||||||
|
.ccu_clk_mgr_base = KONA_MST_CLK_BASE_ADDR, |
||||||
|
}, |
||||||
|
.freq_tbl = master_ahb_freq_tbl, |
||||||
|
.data = &sdio3_ahb_data, |
||||||
|
}; |
||||||
|
|
||||||
|
static struct bus_clock sdio4_ahb_clk = { |
||||||
|
.clk = { |
||||||
|
.name = "sdio4_ahb_clk", |
||||||
|
.parent = &kpm_ccu_clk.clk, |
||||||
|
.ops = &bus_clk_ops, |
||||||
|
.ccu_clk_mgr_base = KONA_MST_CLK_BASE_ADDR, |
||||||
|
}, |
||||||
|
.freq_tbl = master_ahb_freq_tbl, |
||||||
|
.data = &sdio4_ahb_data, |
||||||
|
}; |
||||||
|
|
||||||
|
static struct bus_clock bsc1_apb_clk = { |
||||||
|
.clk = { |
||||||
|
.name = "bsc1_apb_clk", |
||||||
|
.parent = &kps_ccu_clk.clk, |
||||||
|
.ops = &bus_clk_ops, |
||||||
|
.ccu_clk_mgr_base = KONA_SLV_CLK_BASE_ADDR, |
||||||
|
}, |
||||||
|
.freq_tbl = slave_apb_freq_tbl, |
||||||
|
.data = &bsc1_apb_data, |
||||||
|
}; |
||||||
|
|
||||||
|
static struct bus_clock bsc2_apb_clk = { |
||||||
|
.clk = { |
||||||
|
.name = "bsc2_apb_clk", |
||||||
|
.parent = &kps_ccu_clk.clk, |
||||||
|
.ops = &bus_clk_ops, |
||||||
|
.ccu_clk_mgr_base = KONA_SLV_CLK_BASE_ADDR, |
||||||
|
}, |
||||||
|
.freq_tbl = slave_apb_freq_tbl, |
||||||
|
.data = &bsc2_apb_data, |
||||||
|
}; |
||||||
|
|
||||||
|
static struct bus_clock bsc3_apb_clk = { |
||||||
|
.clk = { |
||||||
|
.name = "bsc3_apb_clk", |
||||||
|
.parent = &kps_ccu_clk.clk, |
||||||
|
.ops = &bus_clk_ops, |
||||||
|
.ccu_clk_mgr_base = KONA_SLV_CLK_BASE_ADDR, |
||||||
|
}, |
||||||
|
.freq_tbl = slave_apb_freq_tbl, |
||||||
|
.data = &bsc3_apb_data, |
||||||
|
}; |
||||||
|
|
||||||
|
/* KPM peripheral */ |
||||||
|
static struct peri_clock sdio1_clk = { |
||||||
|
.clk = { |
||||||
|
.name = "sdio1_clk", |
||||||
|
.parent = &ref_52m.clk, |
||||||
|
.ops = &peri_clk_ops, |
||||||
|
.ccu_clk_mgr_base = KONA_MST_CLK_BASE_ADDR, |
||||||
|
}, |
||||||
|
.data = &sdio1_data, |
||||||
|
}; |
||||||
|
|
||||||
|
static struct peri_clock sdio2_clk = { |
||||||
|
.clk = { |
||||||
|
.name = "sdio2_clk", |
||||||
|
.parent = &ref_52m.clk, |
||||||
|
.ops = &peri_clk_ops, |
||||||
|
.ccu_clk_mgr_base = KONA_MST_CLK_BASE_ADDR, |
||||||
|
}, |
||||||
|
.data = &sdio2_data, |
||||||
|
}; |
||||||
|
|
||||||
|
static struct peri_clock sdio3_clk = { |
||||||
|
.clk = { |
||||||
|
.name = "sdio3_clk", |
||||||
|
.parent = &ref_52m.clk, |
||||||
|
.ops = &peri_clk_ops, |
||||||
|
.ccu_clk_mgr_base = KONA_MST_CLK_BASE_ADDR, |
||||||
|
}, |
||||||
|
.data = &sdio3_data, |
||||||
|
}; |
||||||
|
|
||||||
|
static struct peri_clock sdio4_clk = { |
||||||
|
.clk = { |
||||||
|
.name = "sdio4_clk", |
||||||
|
.parent = &ref_52m.clk, |
||||||
|
.ops = &peri_clk_ops, |
||||||
|
.ccu_clk_mgr_base = KONA_MST_CLK_BASE_ADDR, |
||||||
|
}, |
||||||
|
.data = &sdio4_data, |
||||||
|
}; |
||||||
|
|
||||||
|
static struct peri_clock sdio1_sleep_clk = { |
||||||
|
.clk = { |
||||||
|
.name = "sdio1_sleep_clk", |
||||||
|
.parent = &kpm_ccu_clk.clk, |
||||||
|
.ops = &bus_clk_ops, |
||||||
|
.ccu_clk_mgr_base = KONA_MST_CLK_BASE_ADDR, |
||||||
|
}, |
||||||
|
.data = &sdio1_sleep_data, |
||||||
|
}; |
||||||
|
|
||||||
|
static struct peri_clock sdio2_sleep_clk = { |
||||||
|
.clk = { |
||||||
|
.name = "sdio2_sleep_clk", |
||||||
|
.parent = &kpm_ccu_clk.clk, |
||||||
|
.ops = &bus_clk_ops, |
||||||
|
.ccu_clk_mgr_base = KONA_MST_CLK_BASE_ADDR, |
||||||
|
}, |
||||||
|
.data = &sdio2_sleep_data, |
||||||
|
}; |
||||||
|
|
||||||
|
static struct peri_clock sdio3_sleep_clk = { |
||||||
|
.clk = { |
||||||
|
.name = "sdio3_sleep_clk", |
||||||
|
.parent = &kpm_ccu_clk.clk, |
||||||
|
.ops = &bus_clk_ops, |
||||||
|
.ccu_clk_mgr_base = KONA_MST_CLK_BASE_ADDR, |
||||||
|
}, |
||||||
|
.data = &sdio3_sleep_data, |
||||||
|
}; |
||||||
|
|
||||||
|
static struct peri_clock sdio4_sleep_clk = { |
||||||
|
.clk = { |
||||||
|
.name = "sdio4_sleep_clk", |
||||||
|
.parent = &kpm_ccu_clk.clk, |
||||||
|
.ops = &bus_clk_ops, |
||||||
|
.ccu_clk_mgr_base = KONA_MST_CLK_BASE_ADDR, |
||||||
|
}, |
||||||
|
.data = &sdio4_sleep_data, |
||||||
|
}; |
||||||
|
|
||||||
|
/* KPS peripheral clock */ |
||||||
|
static struct peri_clock bsc1_clk = { |
||||||
|
.clk = { |
||||||
|
.name = "bsc1_clk", |
||||||
|
.parent = &ref_13m.clk, |
||||||
|
.rate = 13 * CLOCK_1M, |
||||||
|
.div = 1, |
||||||
|
.ops = &peri_clk_ops, |
||||||
|
.ccu_clk_mgr_base = KONA_SLV_CLK_BASE_ADDR, |
||||||
|
}, |
||||||
|
.data = &bsc1_data, |
||||||
|
}; |
||||||
|
|
||||||
|
static struct peri_clock bsc2_clk = { |
||||||
|
.clk = { |
||||||
|
.name = "bsc2_clk", |
||||||
|
.parent = &ref_13m.clk, |
||||||
|
.rate = 13 * CLOCK_1M, |
||||||
|
.div = 1, |
||||||
|
.ops = &peri_clk_ops, |
||||||
|
.ccu_clk_mgr_base = KONA_SLV_CLK_BASE_ADDR, |
||||||
|
}, |
||||||
|
.data = &bsc2_data, |
||||||
|
}; |
||||||
|
|
||||||
|
static struct peri_clock bsc3_clk = { |
||||||
|
.clk = { |
||||||
|
.name = "bsc3_clk", |
||||||
|
.parent = &ref_13m.clk, |
||||||
|
.rate = 13 * CLOCK_1M, |
||||||
|
.div = 1, |
||||||
|
.ops = &peri_clk_ops, |
||||||
|
.ccu_clk_mgr_base = KONA_SLV_CLK_BASE_ADDR, |
||||||
|
}, |
||||||
|
.data = &bsc3_data, |
||||||
|
}; |
||||||
|
|
||||||
|
/* public table for registering clocks */ |
||||||
|
struct clk_lookup arch_clk_tbl[] = { |
||||||
|
/* Peripheral clocks */ |
||||||
|
CLK_LK(sdio1), |
||||||
|
CLK_LK(sdio2), |
||||||
|
CLK_LK(sdio3), |
||||||
|
CLK_LK(sdio4), |
||||||
|
CLK_LK(sdio1_sleep), |
||||||
|
CLK_LK(sdio2_sleep), |
||||||
|
CLK_LK(sdio3_sleep), |
||||||
|
CLK_LK(sdio4_sleep), |
||||||
|
CLK_LK(bsc1), |
||||||
|
CLK_LK(bsc2), |
||||||
|
CLK_LK(bsc3), |
||||||
|
/* Bus clocks */ |
||||||
|
CLK_LK(usb_otg_ahb), |
||||||
|
CLK_LK(sdio1_ahb), |
||||||
|
CLK_LK(sdio2_ahb), |
||||||
|
CLK_LK(sdio3_ahb), |
||||||
|
CLK_LK(sdio4_ahb), |
||||||
|
CLK_LK(bsc1_apb), |
||||||
|
CLK_LK(bsc2_apb), |
||||||
|
CLK_LK(bsc3_apb), |
||||||
|
#ifdef CONFIG_BCM_SF2_ETH |
||||||
|
CLK_LK(esub_ccu), |
||||||
|
#endif |
||||||
|
}; |
||||||
|
|
||||||
|
/* public array size */ |
||||||
|
unsigned int arch_clk_tbl_array_size = ARRAY_SIZE(arch_clk_tbl); |
@ -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; |
||||||
|
} |
@ -0,0 +1,513 @@ |
|||||||
|
/*
|
||||||
|
* Copyright 2013 Broadcom Corporation. |
||||||
|
* |
||||||
|
* SPDX-License-Identifier: GPL-2.0+ |
||||||
|
*/ |
||||||
|
|
||||||
|
/*
|
||||||
|
* |
||||||
|
* bcm235xx architecture clock framework |
||||||
|
* |
||||||
|
*/ |
||||||
|
|
||||||
|
#include <common.h> |
||||||
|
#include <asm/io.h> |
||||||
|
#include <asm/errno.h> |
||||||
|
#include <bitfield.h> |
||||||
|
#include <asm/arch/sysmap.h> |
||||||
|
#include <asm/kona-common/clk.h> |
||||||
|
#include "clk-core.h" |
||||||
|
|
||||||
|
#define CLK_WR_ACCESS_PASSWORD 0x00a5a501 |
||||||
|
#define WR_ACCESS_OFFSET 0 /* common to all clock blocks */ |
||||||
|
#define POLICY_CTL_GO 1 /* Load and refresh policy masks */ |
||||||
|
#define POLICY_CTL_GO_ATL 4 /* Active Load */ |
||||||
|
|
||||||
|
/* Helper function */ |
||||||
|
int clk_get_and_enable(char *clkstr) |
||||||
|
{ |
||||||
|
int ret = 0; |
||||||
|
struct clk *c; |
||||||
|
|
||||||
|
debug("%s: %s\n", __func__, clkstr); |
||||||
|
|
||||||
|
c = clk_get(clkstr); |
||||||
|
if (c) { |
||||||
|
ret = clk_enable(c); |
||||||
|
if (ret) |
||||||
|
return ret; |
||||||
|
} else { |
||||||
|
printf("%s: Couldn't find %s\n", __func__, clkstr); |
||||||
|
return -EINVAL; |
||||||
|
} |
||||||
|
return ret; |
||||||
|
} |
||||||
|
|
||||||
|
/*
|
||||||
|
* Poll a register in a CCU's address space, returning when the |
||||||
|
* specified bit in that register's value is set (or clear). Delay |
||||||
|
* a microsecond after each read of the register. Returns true if |
||||||
|
* successful, or false if we gave up trying. |
||||||
|
* |
||||||
|
* Caller must ensure the CCU lock is held. |
||||||
|
*/ |
||||||
|
#define CLK_GATE_DELAY_USEC 2000 |
||||||
|
static inline int wait_bit(void *base, u32 offset, u32 bit, bool want) |
||||||
|
{ |
||||||
|
unsigned int tries; |
||||||
|
u32 bit_mask = 1 << bit; |
||||||
|
|
||||||
|
for (tries = 0; tries < CLK_GATE_DELAY_USEC; tries++) { |
||||||
|
u32 val; |
||||||
|
bool bit_val; |
||||||
|
|
||||||
|
val = readl(base + offset); |
||||||
|
bit_val = (val & bit_mask) ? 1 : 0; |
||||||
|
if (bit_val == want) |
||||||
|
return 0; /* success */ |
||||||
|
udelay(1); |
||||||
|
} |
||||||
|
|
||||||
|
debug("%s: timeout on addr 0x%p, waiting for bit %d to go to %d\n", |
||||||
|
__func__, base + offset, bit, want); |
||||||
|
|
||||||
|
return -ETIMEDOUT; |
||||||
|
} |
||||||
|
|
||||||
|
/* Enable a peripheral clock */ |
||||||
|
static int peri_clk_enable(struct clk *c, int enable) |
||||||
|
{ |
||||||
|
int ret = 0; |
||||||
|
u32 reg; |
||||||
|
struct peri_clock *peri_clk = to_peri_clk(c); |
||||||
|
struct peri_clk_data *cd = peri_clk->data; |
||||||
|
struct bcm_clk_gate *gate = &cd->gate; |
||||||
|
void *base = (void *)c->ccu_clk_mgr_base; |
||||||
|
|
||||||
|
|
||||||
|
debug("%s: %s\n", __func__, c->name); |
||||||
|
|
||||||
|
clk_get_rate(c); /* Make sure rate and sel are filled in */ |
||||||
|
|
||||||
|
/* enable access */ |
||||||
|
writel(CLK_WR_ACCESS_PASSWORD, base + WR_ACCESS_OFFSET); |
||||||
|
|
||||||
|
if (enable) { |
||||||
|
debug("%s %s set rate %lu div %lu sel %d parent %lu\n", |
||||||
|
__func__, c->name, c->rate, c->div, c->sel, |
||||||
|
c->parent->rate); |
||||||
|
|
||||||
|
/*
|
||||||
|
* clkgate - only software controllable gates are |
||||||
|
* supported by u-boot which includes all clocks |
||||||
|
* that matter. This avoids bringing in a lot of extra |
||||||
|
* complexity as done in the kernel framework. |
||||||
|
*/ |
||||||
|
if (gate_exists(gate)) { |
||||||
|
reg = readl(base + cd->gate.offset); |
||||||
|
reg |= (1 << cd->gate.en_bit); |
||||||
|
writel(reg, base + cd->gate.offset); |
||||||
|
} |
||||||
|
|
||||||
|
/* div and pll select */ |
||||||
|
if (divider_exists(&cd->div)) { |
||||||
|
reg = readl(base + cd->div.offset); |
||||||
|
bitfield_replace(reg, cd->div.shift, cd->div.width, |
||||||
|
c->div - 1); |
||||||
|
writel(reg, base + cd->div.offset); |
||||||
|
} |
||||||
|
|
||||||
|
/* frequency selector */ |
||||||
|
if (selector_exists(&cd->sel)) { |
||||||
|
reg = readl(base + cd->sel.offset); |
||||||
|
bitfield_replace(reg, cd->sel.shift, cd->sel.width, |
||||||
|
c->sel); |
||||||
|
writel(reg, base + cd->sel.offset); |
||||||
|
} |
||||||
|
|
||||||
|
/* trigger */ |
||||||
|
if (trigger_exists(&cd->trig)) { |
||||||
|
writel((1 << cd->trig.bit), base + cd->trig.offset); |
||||||
|
|
||||||
|
/* wait for trigger status bit to go to 0 */ |
||||||
|
ret = wait_bit(base, cd->trig.offset, cd->trig.bit, 0); |
||||||
|
if (ret) |
||||||
|
return ret; |
||||||
|
} |
||||||
|
|
||||||
|
/* wait for running (status_bit = 1) */ |
||||||
|
ret = wait_bit(base, cd->gate.offset, cd->gate.status_bit, 1); |
||||||
|
if (ret) |
||||||
|
return ret; |
||||||
|
} else { |
||||||
|
debug("%s disable clock %s\n", __func__, c->name); |
||||||
|
|
||||||
|
/* clkgate */ |
||||||
|
reg = readl(base + cd->gate.offset); |
||||||
|
reg &= ~(1 << cd->gate.en_bit); |
||||||
|
writel(reg, base + cd->gate.offset); |
||||||
|
|
||||||
|
/* wait for stop (status_bit = 0) */ |
||||||
|
ret = wait_bit(base, cd->gate.offset, cd->gate.status_bit, 0); |
||||||
|
} |
||||||
|
|
||||||
|
/* disable access */ |
||||||
|
writel(0, base + WR_ACCESS_OFFSET); |
||||||
|
|
||||||
|
return ret; |
||||||
|
} |
||||||
|
|
||||||
|
/* Set the rate of a peripheral clock */ |
||||||
|
static int peri_clk_set_rate(struct clk *c, unsigned long rate) |
||||||
|
{ |
||||||
|
int ret = 0; |
||||||
|
int i; |
||||||
|
unsigned long diff; |
||||||
|
unsigned long new_rate = 0, div = 1; |
||||||
|
struct peri_clock *peri_clk = to_peri_clk(c); |
||||||
|
struct peri_clk_data *cd = peri_clk->data; |
||||||
|
const char **clock; |
||||||
|
|
||||||
|
debug("%s: %s\n", __func__, c->name); |
||||||
|
diff = rate; |
||||||
|
|
||||||
|
i = 0; |
||||||
|
for (clock = cd->clocks; *clock; clock++, i++) { |
||||||
|
struct refclk *ref = refclk_str_to_clk(*clock); |
||||||
|
if (!ref) { |
||||||
|
printf("%s: Lookup of %s failed\n", __func__, *clock); |
||||||
|
return -EINVAL; |
||||||
|
} |
||||||
|
|
||||||
|
/* round to the new rate */ |
||||||
|
div = ref->clk.rate / rate; |
||||||
|
if (div == 0) |
||||||
|
div = 1; |
||||||
|
|
||||||
|
new_rate = ref->clk.rate / div; |
||||||
|
|
||||||
|
/* get the min diff */ |
||||||
|
if (abs(new_rate - rate) < diff) { |
||||||
|
diff = abs(new_rate - rate); |
||||||
|
c->sel = i; |
||||||
|
c->parent = &ref->clk; |
||||||
|
c->rate = new_rate; |
||||||
|
c->div = div; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
debug("%s %s set rate %lu div %lu sel %d parent %lu\n", __func__, |
||||||
|
c->name, c->rate, c->div, c->sel, c->parent->rate); |
||||||
|
return ret; |
||||||
|
} |
||||||
|
|
||||||
|
/* Get the rate of a peripheral clock */ |
||||||
|
static unsigned long peri_clk_get_rate(struct clk *c) |
||||||
|
{ |
||||||
|
struct peri_clock *peri_clk = to_peri_clk(c); |
||||||
|
struct peri_clk_data *cd = peri_clk->data; |
||||||
|
void *base = (void *)c->ccu_clk_mgr_base; |
||||||
|
int div = 1; |
||||||
|
const char **clock; |
||||||
|
struct refclk *ref; |
||||||
|
u32 reg; |
||||||
|
|
||||||
|
debug("%s: %s\n", __func__, c->name); |
||||||
|
if (selector_exists(&cd->sel)) { |
||||||
|
reg = readl(base + cd->sel.offset); |
||||||
|
c->sel = bitfield_extract(reg, cd->sel.shift, cd->sel.width); |
||||||
|
} else { |
||||||
|
/*
|
||||||
|
* For peri clocks that don't have a selector, the single |
||||||
|
* reference clock will always exist at index 0. |
||||||
|
*/ |
||||||
|
c->sel = 0; |
||||||
|
} |
||||||
|
|
||||||
|
if (divider_exists(&cd->div)) { |
||||||
|
reg = readl(base + cd->div.offset); |
||||||
|
div = bitfield_extract(reg, cd->div.shift, cd->div.width); |
||||||
|
div += 1; |
||||||
|
} |
||||||
|
|
||||||
|
clock = cd->clocks; |
||||||
|
ref = refclk_str_to_clk(clock[c->sel]); |
||||||
|
if (!ref) { |
||||||
|
printf("%s: Can't lookup %s\n", __func__, clock[c->sel]); |
||||||
|
return 0; |
||||||
|
} |
||||||
|
|
||||||
|
c->parent = &ref->clk; |
||||||
|
c->div = div; |
||||||
|
c->rate = c->parent->rate / c->div; |
||||||
|
debug("%s parent rate %lu div %d sel %d rate %lu\n", __func__, |
||||||
|
c->parent->rate, div, c->sel, c->rate); |
||||||
|
|
||||||
|
return c->rate; |
||||||
|
} |
||||||
|
|
||||||
|
/* Peripheral clock operations */ |
||||||
|
struct clk_ops peri_clk_ops = { |
||||||
|
.enable = peri_clk_enable, |
||||||
|
.set_rate = peri_clk_set_rate, |
||||||
|
.get_rate = peri_clk_get_rate, |
||||||
|
}; |
||||||
|
|
||||||
|
/* Enable a CCU clock */ |
||||||
|
static int ccu_clk_enable(struct clk *c, int enable) |
||||||
|
{ |
||||||
|
struct ccu_clock *ccu_clk = to_ccu_clk(c); |
||||||
|
void *base = (void *)c->ccu_clk_mgr_base; |
||||||
|
int ret = 0; |
||||||
|
u32 reg; |
||||||
|
|
||||||
|
debug("%s: %s\n", __func__, c->name); |
||||||
|
if (!enable) |
||||||
|
return -EINVAL; /* CCU clock cannot shutdown */ |
||||||
|
|
||||||
|
/* enable access */ |
||||||
|
writel(CLK_WR_ACCESS_PASSWORD, base + WR_ACCESS_OFFSET); |
||||||
|
|
||||||
|
/* config enable for policy engine */ |
||||||
|
writel(1, base + ccu_clk->lvm_en_offset); |
||||||
|
|
||||||
|
/* wait for bit to go to 0 */ |
||||||
|
ret = wait_bit(base, ccu_clk->lvm_en_offset, 0, 0); |
||||||
|
if (ret) |
||||||
|
return ret; |
||||||
|
|
||||||
|
/* freq ID */ |
||||||
|
if (!ccu_clk->freq_bit_shift) |
||||||
|
ccu_clk->freq_bit_shift = 8; |
||||||
|
|
||||||
|
/* Set frequency id for each of the 4 policies */ |
||||||
|
reg = ccu_clk->freq_id | |
||||||
|
(ccu_clk->freq_id << (ccu_clk->freq_bit_shift)) | |
||||||
|
(ccu_clk->freq_id << (ccu_clk->freq_bit_shift * 2)) | |
||||||
|
(ccu_clk->freq_id << (ccu_clk->freq_bit_shift * 3)); |
||||||
|
writel(reg, base + ccu_clk->policy_freq_offset); |
||||||
|
|
||||||
|
/* enable all clock mask */ |
||||||
|
writel(0x7fffffff, base + ccu_clk->policy0_mask_offset); |
||||||
|
writel(0x7fffffff, base + ccu_clk->policy1_mask_offset); |
||||||
|
writel(0x7fffffff, base + ccu_clk->policy2_mask_offset); |
||||||
|
writel(0x7fffffff, base + ccu_clk->policy3_mask_offset); |
||||||
|
|
||||||
|
if (ccu_clk->num_policy_masks == 2) { |
||||||
|
writel(0x7fffffff, base + ccu_clk->policy0_mask2_offset); |
||||||
|
writel(0x7fffffff, base + ccu_clk->policy1_mask2_offset); |
||||||
|
writel(0x7fffffff, base + ccu_clk->policy2_mask2_offset); |
||||||
|
writel(0x7fffffff, base + ccu_clk->policy3_mask2_offset); |
||||||
|
} |
||||||
|
|
||||||
|
/* start policy engine */ |
||||||
|
reg = readl(base + ccu_clk->policy_ctl_offset); |
||||||
|
reg |= (POLICY_CTL_GO + POLICY_CTL_GO_ATL); |
||||||
|
writel(reg, base + ccu_clk->policy_ctl_offset); |
||||||
|
|
||||||
|
/* wait till started */ |
||||||
|
ret = wait_bit(base, ccu_clk->policy_ctl_offset, 0, 0); |
||||||
|
if (ret) |
||||||
|
return ret; |
||||||
|
|
||||||
|
/* disable access */ |
||||||
|
writel(0, base + WR_ACCESS_OFFSET); |
||||||
|
|
||||||
|
return ret; |
||||||
|
} |
||||||
|
|
||||||
|
/* Get the CCU clock rate */ |
||||||
|
static unsigned long ccu_clk_get_rate(struct clk *c) |
||||||
|
{ |
||||||
|
struct ccu_clock *ccu_clk = to_ccu_clk(c); |
||||||
|
debug("%s: %s\n", __func__, c->name); |
||||||
|
c->rate = ccu_clk->freq_tbl[ccu_clk->freq_id]; |
||||||
|
return c->rate; |
||||||
|
} |
||||||
|
|
||||||
|
/* CCU clock operations */ |
||||||
|
struct clk_ops ccu_clk_ops = { |
||||||
|
.enable = ccu_clk_enable, |
||||||
|
.get_rate = ccu_clk_get_rate, |
||||||
|
}; |
||||||
|
|
||||||
|
/* Enable a bus clock */ |
||||||
|
static int bus_clk_enable(struct clk *c, int enable) |
||||||
|
{ |
||||||
|
struct bus_clock *bus_clk = to_bus_clk(c); |
||||||
|
struct bus_clk_data *cd = bus_clk->data; |
||||||
|
void *base = (void *)c->ccu_clk_mgr_base; |
||||||
|
int ret = 0; |
||||||
|
u32 reg; |
||||||
|
|
||||||
|
debug("%s: %s\n", __func__, c->name); |
||||||
|
/* enable access */ |
||||||
|
writel(CLK_WR_ACCESS_PASSWORD, base + WR_ACCESS_OFFSET); |
||||||
|
|
||||||
|
/* enable gating */ |
||||||
|
reg = readl(base + cd->gate.offset); |
||||||
|
if (!!(reg & (1 << cd->gate.status_bit)) == !!enable) |
||||||
|
debug("%s already %s\n", c->name, |
||||||
|
enable ? "enabled" : "disabled"); |
||||||
|
else { |
||||||
|
int want = (enable) ? 1 : 0; |
||||||
|
reg |= (1 << cd->gate.hw_sw_sel_bit); |
||||||
|
|
||||||
|
if (enable) |
||||||
|
reg |= (1 << cd->gate.en_bit); |
||||||
|
else |
||||||
|
reg &= ~(1 << cd->gate.en_bit); |
||||||
|
|
||||||
|
writel(reg, base + cd->gate.offset); |
||||||
|
ret = wait_bit(base, cd->gate.offset, cd->gate.status_bit, |
||||||
|
want); |
||||||
|
if (ret) |
||||||
|
return ret; |
||||||
|
} |
||||||
|
|
||||||
|
/* disable access */ |
||||||
|
writel(0, base + WR_ACCESS_OFFSET); |
||||||
|
|
||||||
|
return ret; |
||||||
|
} |
||||||
|
|
||||||
|
/* Get the rate of a bus clock */ |
||||||
|
static unsigned long bus_clk_get_rate(struct clk *c) |
||||||
|
{ |
||||||
|
struct bus_clock *bus_clk = to_bus_clk(c); |
||||||
|
struct ccu_clock *ccu_clk; |
||||||
|
|
||||||
|
debug("%s: %s\n", __func__, c->name); |
||||||
|
ccu_clk = to_ccu_clk(c->parent); |
||||||
|
|
||||||
|
c->rate = bus_clk->freq_tbl[ccu_clk->freq_id]; |
||||||
|
c->div = ccu_clk->freq_tbl[ccu_clk->freq_id] / c->rate; |
||||||
|
return c->rate; |
||||||
|
} |
||||||
|
|
||||||
|
/* Bus clock operations */ |
||||||
|
struct clk_ops bus_clk_ops = { |
||||||
|
.enable = bus_clk_enable, |
||||||
|
.get_rate = bus_clk_get_rate, |
||||||
|
}; |
||||||
|
|
||||||
|
/* Enable a reference clock */ |
||||||
|
static int ref_clk_enable(struct clk *c, int enable) |
||||||
|
{ |
||||||
|
debug("%s: %s\n", __func__, c->name); |
||||||
|
return 0; |
||||||
|
} |
||||||
|
|
||||||
|
/* Reference clock operations */ |
||||||
|
struct clk_ops ref_clk_ops = { |
||||||
|
.enable = ref_clk_enable, |
||||||
|
}; |
||||||
|
|
||||||
|
/*
|
||||||
|
* clk.h implementation follows |
||||||
|
*/ |
||||||
|
|
||||||
|
/* Initialize the clock framework */ |
||||||
|
int clk_init(void) |
||||||
|
{ |
||||||
|
debug("%s:\n", __func__); |
||||||
|
return 0; |
||||||
|
} |
||||||
|
|
||||||
|
/* Get a clock handle, give a name string */ |
||||||
|
struct clk *clk_get(const char *con_id) |
||||||
|
{ |
||||||
|
int i; |
||||||
|
struct clk_lookup *clk_tblp; |
||||||
|
|
||||||
|
debug("%s: %s\n", __func__, con_id); |
||||||
|
|
||||||
|
clk_tblp = arch_clk_tbl; |
||||||
|
for (i = 0; i < arch_clk_tbl_array_size; i++, clk_tblp++) { |
||||||
|
if (clk_tblp->con_id) { |
||||||
|
if (!con_id || strcmp(clk_tblp->con_id, con_id)) |
||||||
|
continue; |
||||||
|
return clk_tblp->clk; |
||||||
|
} |
||||||
|
} |
||||||
|
return NULL; |
||||||
|
} |
||||||
|
|
||||||
|
/* Enable a clock */ |
||||||
|
int clk_enable(struct clk *c) |
||||||
|
{ |
||||||
|
int ret = 0; |
||||||
|
|
||||||
|
debug("%s: %s\n", __func__, c->name); |
||||||
|
if (!c->ops || !c->ops->enable) |
||||||
|
return -1; |
||||||
|
|
||||||
|
/* enable parent clock first */ |
||||||
|
if (c->parent) |
||||||
|
ret = clk_enable(c->parent); |
||||||
|
|
||||||
|
if (ret) |
||||||
|
return ret; |
||||||
|
|
||||||
|
if (!c->use_cnt) { |
||||||
|
c->use_cnt++; |
||||||
|
ret = c->ops->enable(c, 1); |
||||||
|
} |
||||||
|
|
||||||
|
return ret; |
||||||
|
} |
||||||
|
|
||||||
|
/* Disable a clock */ |
||||||
|
void clk_disable(struct clk *c) |
||||||
|
{ |
||||||
|
debug("%s: %s\n", __func__, c->name); |
||||||
|
if (!c->ops || !c->ops->enable) |
||||||
|
return; |
||||||
|
|
||||||
|
if (c->use_cnt) { |
||||||
|
c->use_cnt--; |
||||||
|
c->ops->enable(c, 0); |
||||||
|
} |
||||||
|
|
||||||
|
/* disable parent */ |
||||||
|
if (c->parent) |
||||||
|
clk_disable(c->parent); |
||||||
|
} |
||||||
|
|
||||||
|
/* Get the clock rate */ |
||||||
|
unsigned long clk_get_rate(struct clk *c) |
||||||
|
{ |
||||||
|
unsigned long rate; |
||||||
|
|
||||||
|
debug("%s: %s\n", __func__, c->name); |
||||||
|
if (!c || !c->ops || !c->ops->get_rate) |
||||||
|
return 0; |
||||||
|
|
||||||
|
rate = c->ops->get_rate(c); |
||||||
|
debug("%s: rate = %ld\n", __func__, rate); |
||||||
|
return rate; |
||||||
|
} |
||||||
|
|
||||||
|
/* Set the clock rate */ |
||||||
|
int clk_set_rate(struct clk *c, unsigned long rate) |
||||||
|
{ |
||||||
|
int ret; |
||||||
|
|
||||||
|
debug("%s: %s rate=%ld\n", __func__, c->name, rate); |
||||||
|
if (!c || !c->ops || !c->ops->set_rate) |
||||||
|
return -EINVAL; |
||||||
|
|
||||||
|
if (c->use_cnt) |
||||||
|
return -EINVAL; |
||||||
|
|
||||||
|
ret = c->ops->set_rate(c, rate); |
||||||
|
|
||||||
|
return ret; |
||||||
|
} |
||||||
|
|
||||||
|
/* Not required for this arch */ |
||||||
|
/*
|
||||||
|
long clk_round_rate(struct clk *clk, unsigned long rate); |
||||||
|
int clk_set_parent(struct clk *clk, struct clk *parent); |
||||||
|
struct clk *clk_get_parent(struct clk *clk); |
||||||
|
*/ |
@ -0,0 +1,491 @@ |
|||||||
|
/*
|
||||||
|
* Copyright 2013 Broadcom Corporation. |
||||||
|
* |
||||||
|
* SPDX-License-Identifier: GPL-2.0+ |
||||||
|
*/ |
||||||
|
|
||||||
|
#include <linux/stddef.h> |
||||||
|
|
||||||
|
#ifdef CONFIG_CLK_DEBUG |
||||||
|
#undef writel |
||||||
|
#undef readl |
||||||
|
static inline void writel(u32 val, void *addr) |
||||||
|
{ |
||||||
|
printf("Write [0x%p] = 0x%08x\n", addr, val); |
||||||
|
*(u32 *)addr = val; |
||||||
|
} |
||||||
|
|
||||||
|
static inline u32 readl(void *addr) |
||||||
|
{ |
||||||
|
u32 val = *(u32 *)addr; |
||||||
|
printf("Read [0x%p] = 0x%08x\n", addr, val); |
||||||
|
return val; |
||||||
|
} |
||||||
|
#endif |
||||||
|
|
||||||
|
struct clk; |
||||||
|
|
||||||
|
struct clk_lookup { |
||||||
|
const char *dev_id; |
||||||
|
const char *con_id; |
||||||
|
struct clk *clk; |
||||||
|
}; |
||||||
|
|
||||||
|
extern struct clk_lookup arch_clk_tbl[]; |
||||||
|
extern unsigned int arch_clk_tbl_array_size; |
||||||
|
|
||||||
|
/**
|
||||||
|
* struct clk_ops - standard clock operations |
||||||
|
* @enable: enable/disable clock, see clk_enable() and clk_disable() |
||||||
|
* @set_rate: set the clock rate, see clk_set_rate(). |
||||||
|
* @get_rate: get the clock rate, see clk_get_rate(). |
||||||
|
* @round_rate: round a given clock rate, see clk_round_rate(). |
||||||
|
* @set_parent: set the clock's parent, see clk_set_parent(). |
||||||
|
* |
||||||
|
* Group the common clock implementations together so that we |
||||||
|
* don't have to keep setting the same fiels again. We leave |
||||||
|
* enable in struct clk. |
||||||
|
* |
||||||
|
*/ |
||||||
|
struct clk_ops { |
||||||
|
int (*enable)(struct clk *c, int enable); |
||||||
|
int (*set_rate)(struct clk *c, unsigned long rate); |
||||||
|
unsigned long (*get_rate)(struct clk *c); |
||||||
|
unsigned long (*round_rate)(struct clk *c, unsigned long rate); |
||||||
|
int (*set_parent)(struct clk *c, struct clk *parent); |
||||||
|
}; |
||||||
|
|
||||||
|
struct clk { |
||||||
|
struct clk *parent; |
||||||
|
const char *name; |
||||||
|
int use_cnt; |
||||||
|
unsigned long rate; /* in HZ */ |
||||||
|
|
||||||
|
/* programmable divider. 0 means fixed ratio to parent clock */ |
||||||
|
unsigned long div; |
||||||
|
|
||||||
|
struct clk_src *src; |
||||||
|
struct clk_ops *ops; |
||||||
|
|
||||||
|
unsigned long ccu_clk_mgr_base; |
||||||
|
int sel; |
||||||
|
}; |
||||||
|
|
||||||
|
struct refclk *refclk_str_to_clk(const char *name); |
||||||
|
|
||||||
|
/* The common clock framework uses u8 to represent a parent index */ |
||||||
|
#define PARENT_COUNT_MAX ((u32)U8_MAX) |
||||||
|
|
||||||
|
#define BAD_CLK_INDEX U8_MAX /* Can't ever be valid */ |
||||||
|
#define BAD_CLK_NAME ((const char *)-1) |
||||||
|
|
||||||
|
#define BAD_SCALED_DIV_VALUE U64_MAX |
||||||
|
|
||||||
|
/*
|
||||||
|
* Utility macros for object flag management. If possible, flags |
||||||
|
* should be defined such that 0 is the desired default value. |
||||||
|
*/ |
||||||
|
#define FLAG(type, flag) BCM_CLK_ ## type ## _FLAGS_ ## flag |
||||||
|
#define FLAG_SET(obj, type, flag) ((obj)->flags |= FLAG(type, flag)) |
||||||
|
#define FLAG_CLEAR(obj, type, flag) ((obj)->flags &= ~(FLAG(type, flag))) |
||||||
|
#define FLAG_FLIP(obj, type, flag) ((obj)->flags ^= FLAG(type, flag)) |
||||||
|
#define FLAG_TEST(obj, type, flag) (!!((obj)->flags & FLAG(type, flag))) |
||||||
|
|
||||||
|
/* Clock field state tests */ |
||||||
|
|
||||||
|
#define gate_exists(gate) FLAG_TEST(gate, GATE, EXISTS) |
||||||
|
#define gate_is_enabled(gate) FLAG_TEST(gate, GATE, ENABLED) |
||||||
|
#define gate_is_hw_controllable(gate) FLAG_TEST(gate, GATE, HW) |
||||||
|
#define gate_is_sw_controllable(gate) FLAG_TEST(gate, GATE, SW) |
||||||
|
#define gate_is_sw_managed(gate) FLAG_TEST(gate, GATE, SW_MANAGED) |
||||||
|
#define gate_is_no_disable(gate) FLAG_TEST(gate, GATE, NO_DISABLE) |
||||||
|
|
||||||
|
#define gate_flip_enabled(gate) FLAG_FLIP(gate, GATE, ENABLED) |
||||||
|
|
||||||
|
#define divider_exists(div) FLAG_TEST(div, DIV, EXISTS) |
||||||
|
#define divider_is_fixed(div) FLAG_TEST(div, DIV, FIXED) |
||||||
|
#define divider_has_fraction(div) (!divider_is_fixed(div) && \ |
||||||
|
(div)->frac_width > 0) |
||||||
|
|
||||||
|
#define selector_exists(sel) ((sel)->width != 0) |
||||||
|
#define trigger_exists(trig) FLAG_TEST(trig, TRIG, EXISTS) |
||||||
|
|
||||||
|
/* Clock type, used to tell common block what it's part of */ |
||||||
|
enum bcm_clk_type { |
||||||
|
bcm_clk_none, /* undefined clock type */ |
||||||
|
bcm_clk_bus, |
||||||
|
bcm_clk_core, |
||||||
|
bcm_clk_peri |
||||||
|
}; |
||||||
|
|
||||||
|
/*
|
||||||
|
* Gating control and status is managed by a 32-bit gate register. |
||||||
|
* |
||||||
|
* There are several types of gating available: |
||||||
|
* - (no gate) |
||||||
|
* A clock with no gate is assumed to be always enabled. |
||||||
|
* - hardware-only gating (auto-gating) |
||||||
|
* Enabling or disabling clocks with this type of gate is |
||||||
|
* managed automatically by the hardware. Such clocks can be |
||||||
|
* considered by the software to be enabled. The current status |
||||||
|
* of auto-gated clocks can be read from the gate status bit. |
||||||
|
* - software-only gating |
||||||
|
* Auto-gating is not available for this type of clock. |
||||||
|
* Instead, software manages whether it's enabled by setting or |
||||||
|
* clearing the enable bit. The current gate status of a gate |
||||||
|
* under software control can be read from the gate status bit. |
||||||
|
* To ensure a change to the gating status is complete, the |
||||||
|
* status bit can be polled to verify that the gate has entered |
||||||
|
* the desired state. |
||||||
|
* - selectable hardware or software gating |
||||||
|
* Gating for this type of clock can be configured to be either |
||||||
|
* under software or hardware control. Which type is in use is |
||||||
|
* determined by the hw_sw_sel bit of the gate register. |
||||||
|
*/ |
||||||
|
struct bcm_clk_gate { |
||||||
|
u32 offset; /* gate register offset */ |
||||||
|
u32 status_bit; /* 0: gate is disabled; 0: gatge is enabled */ |
||||||
|
u32 en_bit; /* 0: disable; 1: enable */ |
||||||
|
u32 hw_sw_sel_bit; /* 0: hardware gating; 1: software gating */ |
||||||
|
u32 flags; /* BCM_CLK_GATE_FLAGS_* below */ |
||||||
|
}; |
||||||
|
|
||||||
|
/*
|
||||||
|
* Gate flags: |
||||||
|
* HW means this gate can be auto-gated |
||||||
|
* SW means the state of this gate can be software controlled |
||||||
|
* NO_DISABLE means this gate is (only) enabled if under software control |
||||||
|
* SW_MANAGED means the status of this gate is under software control |
||||||
|
* ENABLED means this software-managed gate is *supposed* to be enabled |
||||||
|
*/ |
||||||
|
#define BCM_CLK_GATE_FLAGS_EXISTS ((u32)1 << 0) /* Gate is valid */ |
||||||
|
#define BCM_CLK_GATE_FLAGS_HW ((u32)1 << 1) /* Can auto-gate */ |
||||||
|
#define BCM_CLK_GATE_FLAGS_SW ((u32)1 << 2) /* Software control */ |
||||||
|
#define BCM_CLK_GATE_FLAGS_NO_DISABLE ((u32)1 << 3) /* HW or enabled */ |
||||||
|
#define BCM_CLK_GATE_FLAGS_SW_MANAGED ((u32)1 << 4) /* SW now in control */ |
||||||
|
#define BCM_CLK_GATE_FLAGS_ENABLED ((u32)1 << 5) /* If SW_MANAGED */ |
||||||
|
|
||||||
|
/*
|
||||||
|
* Gate initialization macros. |
||||||
|
* |
||||||
|
* Any gate initially under software control will be enabled. |
||||||
|
*/ |
||||||
|
|
||||||
|
/* A hardware/software gate initially under software control */ |
||||||
|
#define HW_SW_GATE(_offset, _status_bit, _en_bit, _hw_sw_sel_bit) \ |
||||||
|
{ \
|
||||||
|
.offset = (_offset), \
|
||||||
|
.status_bit = (_status_bit), \
|
||||||
|
.en_bit = (_en_bit), \
|
||||||
|
.hw_sw_sel_bit = (_hw_sw_sel_bit), \
|
||||||
|
.flags = FLAG(GATE, HW)|FLAG(GATE, SW)| \
|
||||||
|
FLAG(GATE, SW_MANAGED)|FLAG(GATE, ENABLED)| \
|
||||||
|
FLAG(GATE, EXISTS), \
|
||||||
|
} |
||||||
|
|
||||||
|
/* A hardware/software gate initially under hardware control */ |
||||||
|
#define HW_SW_GATE_AUTO(_offset, _status_bit, _en_bit, _hw_sw_sel_bit) \ |
||||||
|
{ \
|
||||||
|
.offset = (_offset), \
|
||||||
|
.status_bit = (_status_bit), \
|
||||||
|
.en_bit = (_en_bit), \
|
||||||
|
.hw_sw_sel_bit = (_hw_sw_sel_bit), \
|
||||||
|
.flags = FLAG(GATE, HW)|FLAG(GATE, SW)| \
|
||||||
|
FLAG(GATE, EXISTS), \
|
||||||
|
} |
||||||
|
|
||||||
|
/* A hardware-or-enabled gate (enabled if not under hardware control) */ |
||||||
|
#define HW_ENABLE_GATE(_offset, _status_bit, _en_bit, _hw_sw_sel_bit) \ |
||||||
|
{ \
|
||||||
|
.offset = (_offset), \
|
||||||
|
.status_bit = (_status_bit), \
|
||||||
|
.en_bit = (_en_bit), \
|
||||||
|
.hw_sw_sel_bit = (_hw_sw_sel_bit), \
|
||||||
|
.flags = FLAG(GATE, HW)|FLAG(GATE, SW)| \
|
||||||
|
FLAG(GATE, NO_DISABLE)|FLAG(GATE, EXISTS), \
|
||||||
|
} |
||||||
|
|
||||||
|
/* A software-only gate */ |
||||||
|
#define SW_ONLY_GATE(_offset, _status_bit, _en_bit) \ |
||||||
|
{ \
|
||||||
|
.offset = (_offset), \
|
||||||
|
.status_bit = (_status_bit), \
|
||||||
|
.en_bit = (_en_bit), \
|
||||||
|
.flags = FLAG(GATE, SW)|FLAG(GATE, SW_MANAGED)| \
|
||||||
|
FLAG(GATE, ENABLED)|FLAG(GATE, EXISTS), \
|
||||||
|
} |
||||||
|
|
||||||
|
/* A hardware-only gate */ |
||||||
|
#define HW_ONLY_GATE(_offset, _status_bit) \ |
||||||
|
{ \
|
||||||
|
.offset = (_offset), \
|
||||||
|
.status_bit = (_status_bit), \
|
||||||
|
.flags = FLAG(GATE, HW)|FLAG(GATE, EXISTS), \
|
||||||
|
} |
||||||
|
|
||||||
|
/*
|
||||||
|
* Each clock can have zero, one, or two dividers which change the |
||||||
|
* output rate of the clock. Each divider can be either fixed or |
||||||
|
* variable. If there are two dividers, they are the "pre-divider" |
||||||
|
* and the "regular" or "downstream" divider. If there is only one, |
||||||
|
* there is no pre-divider. |
||||||
|
* |
||||||
|
* A fixed divider is any non-zero (positive) value, and it |
||||||
|
* indicates how the input rate is affected by the divider. |
||||||
|
* |
||||||
|
* The value of a variable divider is maintained in a sub-field of a |
||||||
|
* 32-bit divider register. The position of the field in the |
||||||
|
* register is defined by its offset and width. The value recorded |
||||||
|
* in this field is always 1 less than the value it represents. |
||||||
|
* |
||||||
|
* In addition, a variable divider can indicate that some subset |
||||||
|
* of its bits represent a "fractional" part of the divider. Such |
||||||
|
* bits comprise the low-order portion of the divider field, and can |
||||||
|
* be viewed as representing the portion of the divider that lies to |
||||||
|
* the right of the decimal point. Most variable dividers have zero |
||||||
|
* fractional bits. Variable dividers with non-zero fraction width |
||||||
|
* still record a value 1 less than the value they represent; the |
||||||
|
* added 1 does *not* affect the low-order bit in this case, it |
||||||
|
* affects the bits above the fractional part only. (Often in this |
||||||
|
* code a divider field value is distinguished from the value it |
||||||
|
* represents by referring to the latter as a "divisor".) |
||||||
|
* |
||||||
|
* In order to avoid dealing with fractions, divider arithmetic is |
||||||
|
* performed using "scaled" values. A scaled value is one that's |
||||||
|
* been left-shifted by the fractional width of a divider. Dividing |
||||||
|
* a scaled value by a scaled divisor produces the desired quotient |
||||||
|
* without loss of precision and without any other special handling |
||||||
|
* for fractions. |
||||||
|
* |
||||||
|
* The recorded value of a variable divider can be modified. To |
||||||
|
* modify either divider (or both), a clock must be enabled (i.e., |
||||||
|
* using its gate). In addition, a trigger register (described |
||||||
|
* below) must be used to commit the change, and polled to verify |
||||||
|
* the change is complete. |
||||||
|
*/ |
||||||
|
struct bcm_clk_div { |
||||||
|
union { |
||||||
|
struct { /* variable divider */ |
||||||
|
u32 offset; /* divider register offset */ |
||||||
|
u32 shift; /* field shift */ |
||||||
|
u32 width; /* field width */ |
||||||
|
u32 frac_width; /* field fraction width */ |
||||||
|
|
||||||
|
u64 scaled_div; /* scaled divider value */ |
||||||
|
}; |
||||||
|
u32 fixed; /* non-zero fixed divider value */ |
||||||
|
}; |
||||||
|
u32 flags; /* BCM_CLK_DIV_FLAGS_* below */ |
||||||
|
}; |
||||||
|
|
||||||
|
/*
|
||||||
|
* Divider flags: |
||||||
|
* EXISTS means this divider exists |
||||||
|
* FIXED means it is a fixed-rate divider |
||||||
|
*/ |
||||||
|
#define BCM_CLK_DIV_FLAGS_EXISTS ((u32)1 << 0) /* Divider is valid */ |
||||||
|
#define BCM_CLK_DIV_FLAGS_FIXED ((u32)1 << 1) /* Fixed-value */ |
||||||
|
|
||||||
|
/* Divider initialization macros */ |
||||||
|
|
||||||
|
/* A fixed (non-zero) divider */ |
||||||
|
#define FIXED_DIVIDER(_value) \ |
||||||
|
{ \
|
||||||
|
.fixed = (_value), \
|
||||||
|
.flags = FLAG(DIV, EXISTS)|FLAG(DIV, FIXED), \
|
||||||
|
} |
||||||
|
|
||||||
|
/* A divider with an integral divisor */ |
||||||
|
#define DIVIDER(_offset, _shift, _width) \ |
||||||
|
{ \
|
||||||
|
.offset = (_offset), \
|
||||||
|
.shift = (_shift), \
|
||||||
|
.width = (_width), \
|
||||||
|
.scaled_div = BAD_SCALED_DIV_VALUE, \
|
||||||
|
.flags = FLAG(DIV, EXISTS), \
|
||||||
|
} |
||||||
|
|
||||||
|
/* A divider whose divisor has an integer and fractional part */ |
||||||
|
#define FRAC_DIVIDER(_offset, _shift, _width, _frac_width) \ |
||||||
|
{ \
|
||||||
|
.offset = (_offset), \
|
||||||
|
.shift = (_shift), \
|
||||||
|
.width = (_width), \
|
||||||
|
.frac_width = (_frac_width), \
|
||||||
|
.scaled_div = BAD_SCALED_DIV_VALUE, \
|
||||||
|
.flags = FLAG(DIV, EXISTS), \
|
||||||
|
} |
||||||
|
|
||||||
|
/*
|
||||||
|
* Clocks may have multiple "parent" clocks. If there is more than |
||||||
|
* one, a selector must be specified to define which of the parent |
||||||
|
* clocks is currently in use. The selected clock is indicated in a |
||||||
|
* sub-field of a 32-bit selector register. The range of |
||||||
|
* representable selector values typically exceeds the number of |
||||||
|
* available parent clocks. Occasionally the reset value of a |
||||||
|
* selector field is explicitly set to a (specific) value that does |
||||||
|
* not correspond to a defined input clock. |
||||||
|
* |
||||||
|
* We register all known parent clocks with the common clock code |
||||||
|
* using a packed array (i.e., no empty slots) of (parent) clock |
||||||
|
* names, and refer to them later using indexes into that array. |
||||||
|
* We maintain an array of selector values indexed by common clock |
||||||
|
* index values in order to map between these common clock indexes |
||||||
|
* and the selector values used by the hardware. |
||||||
|
* |
||||||
|
* Like dividers, a selector can be modified, but to do so a clock |
||||||
|
* must be enabled, and a trigger must be used to commit the change. |
||||||
|
*/ |
||||||
|
struct bcm_clk_sel { |
||||||
|
u32 offset; /* selector register offset */ |
||||||
|
u32 shift; /* field shift */ |
||||||
|
u32 width; /* field width */ |
||||||
|
|
||||||
|
u32 parent_count; /* number of entries in parent_sel[] */ |
||||||
|
u32 *parent_sel; /* array of parent selector values */ |
||||||
|
u8 clk_index; /* current selected index in parent_sel[] */ |
||||||
|
}; |
||||||
|
|
||||||
|
/* Selector initialization macro */ |
||||||
|
#define SELECTOR(_offset, _shift, _width) \ |
||||||
|
{ \
|
||||||
|
.offset = (_offset), \
|
||||||
|
.shift = (_shift), \
|
||||||
|
.width = (_width), \
|
||||||
|
.clk_index = BAD_CLK_INDEX, \
|
||||||
|
} |
||||||
|
|
||||||
|
/*
|
||||||
|
* Making changes to a variable divider or a selector for a clock |
||||||
|
* requires the use of a trigger. A trigger is defined by a single |
||||||
|
* bit within a register. To signal a change, a 1 is written into |
||||||
|
* that bit. To determine when the change has been completed, that |
||||||
|
* trigger bit is polled; the read value will be 1 while the change |
||||||
|
* is in progress, and 0 when it is complete. |
||||||
|
* |
||||||
|
* Occasionally a clock will have more than one trigger. In this |
||||||
|
* case, the "pre-trigger" will be used when changing a clock's |
||||||
|
* selector and/or its pre-divider. |
||||||
|
*/ |
||||||
|
struct bcm_clk_trig { |
||||||
|
u32 offset; /* trigger register offset */ |
||||||
|
u32 bit; /* trigger bit */ |
||||||
|
u32 flags; /* BCM_CLK_TRIG_FLAGS_* below */ |
||||||
|
}; |
||||||
|
|
||||||
|
/*
|
||||||
|
* Trigger flags: |
||||||
|
* EXISTS means this trigger exists |
||||||
|
*/ |
||||||
|
#define BCM_CLK_TRIG_FLAGS_EXISTS ((u32)1 << 0) /* Trigger is valid */ |
||||||
|
|
||||||
|
/* Trigger initialization macro */ |
||||||
|
#define TRIGGER(_offset, _bit) \ |
||||||
|
{ \
|
||||||
|
.offset = (_offset), \
|
||||||
|
.bit = (_bit), \
|
||||||
|
.flags = FLAG(TRIG, EXISTS), \
|
||||||
|
} |
||||||
|
|
||||||
|
struct bus_clk_data { |
||||||
|
struct bcm_clk_gate gate; |
||||||
|
}; |
||||||
|
|
||||||
|
struct core_clk_data { |
||||||
|
struct bcm_clk_gate gate; |
||||||
|
}; |
||||||
|
|
||||||
|
struct peri_clk_data { |
||||||
|
struct bcm_clk_gate gate; |
||||||
|
struct bcm_clk_trig pre_trig; |
||||||
|
struct bcm_clk_div pre_div; |
||||||
|
struct bcm_clk_trig trig; |
||||||
|
struct bcm_clk_div div; |
||||||
|
struct bcm_clk_sel sel; |
||||||
|
const char *clocks[]; /* must be last; use CLOCKS() to declare */ |
||||||
|
}; |
||||||
|
#define CLOCKS(...) { __VA_ARGS__, NULL, } |
||||||
|
#define NO_CLOCKS { NULL, } /* Must use of no parent clocks */ |
||||||
|
|
||||||
|
struct refclk { |
||||||
|
struct clk clk; |
||||||
|
}; |
||||||
|
|
||||||
|
struct peri_clock { |
||||||
|
struct clk clk; |
||||||
|
struct peri_clk_data *data; |
||||||
|
}; |
||||||
|
|
||||||
|
struct ccu_clock { |
||||||
|
struct clk clk; |
||||||
|
|
||||||
|
int num_policy_masks; |
||||||
|
unsigned long policy_freq_offset; |
||||||
|
int freq_bit_shift; /* 8 for most CCUs */ |
||||||
|
unsigned long policy_ctl_offset; |
||||||
|
unsigned long policy0_mask_offset; |
||||||
|
unsigned long policy1_mask_offset; |
||||||
|
unsigned long policy2_mask_offset; |
||||||
|
unsigned long policy3_mask_offset; |
||||||
|
unsigned long policy0_mask2_offset; |
||||||
|
unsigned long policy1_mask2_offset; |
||||||
|
unsigned long policy2_mask2_offset; |
||||||
|
unsigned long policy3_mask2_offset; |
||||||
|
unsigned long lvm_en_offset; |
||||||
|
|
||||||
|
int freq_id; |
||||||
|
unsigned long *freq_tbl; |
||||||
|
}; |
||||||
|
|
||||||
|
struct bus_clock { |
||||||
|
struct clk clk; |
||||||
|
struct bus_clk_data *data; |
||||||
|
unsigned long *freq_tbl; |
||||||
|
}; |
||||||
|
|
||||||
|
struct ref_clock { |
||||||
|
struct clk clk; |
||||||
|
}; |
||||||
|
|
||||||
|
static inline int is_same_clock(struct clk *a, struct clk *b) |
||||||
|
{ |
||||||
|
return a == b; |
||||||
|
} |
||||||
|
|
||||||
|
#define to_clk(p) (&((p)->clk)) |
||||||
|
#define name_to_clk(name) (&((name##_clk).clk)) |
||||||
|
/* declare a struct clk_lookup */ |
||||||
|
#define CLK_LK(name) \ |
||||||
|
{.con_id = __stringify(name##_clk), .clk = name_to_clk(name),} |
||||||
|
|
||||||
|
static inline struct refclk *to_refclk(struct clk *clock) |
||||||
|
{ |
||||||
|
return container_of(clock, struct refclk, clk); |
||||||
|
} |
||||||
|
|
||||||
|
static inline struct peri_clock *to_peri_clk(struct clk *clock) |
||||||
|
{ |
||||||
|
return container_of(clock, struct peri_clock, clk); |
||||||
|
} |
||||||
|
|
||||||
|
static inline struct ccu_clock *to_ccu_clk(struct clk *clock) |
||||||
|
{ |
||||||
|
return container_of(clock, struct ccu_clock, clk); |
||||||
|
} |
||||||
|
|
||||||
|
static inline struct bus_clock *to_bus_clk(struct clk *clock) |
||||||
|
{ |
||||||
|
return container_of(clock, struct bus_clock, clk); |
||||||
|
} |
||||||
|
|
||||||
|
static inline struct ref_clock *to_ref_clk(struct clk *clock) |
||||||
|
{ |
||||||
|
return container_of(clock, struct ref_clock, clk); |
||||||
|
} |
||||||
|
|
||||||
|
extern struct clk_ops peri_clk_ops; |
||||||
|
extern struct clk_ops ccu_clk_ops; |
||||||
|
extern struct clk_ops bus_clk_ops; |
||||||
|
extern struct clk_ops ref_clk_ops; |
||||||
|
|
||||||
|
int clk_get_and_enable(char *clkstr); |
@ -0,0 +1,143 @@ |
|||||||
|
/*
|
||||||
|
* Copyright 2014 Broadcom Corporation. |
||||||
|
* |
||||||
|
* SPDX-License-Identifier: GPL-2.0+ |
||||||
|
*/ |
||||||
|
|
||||||
|
#include <common.h> |
||||||
|
#include <asm/io.h> |
||||||
|
#include <asm/errno.h> |
||||||
|
#include <asm/arch/sysmap.h> |
||||||
|
#include <asm/kona-common/clk.h> |
||||||
|
#include "clk-core.h" |
||||||
|
|
||||||
|
#define WR_ACCESS_ADDR ESUB_CLK_BASE_ADDR |
||||||
|
#define WR_ACCESS_PASSWORD 0xA5A500 |
||||||
|
|
||||||
|
#define PLLE_POST_RESETB_ADDR (ESUB_CLK_BASE_ADDR + 0x00000C00) |
||||||
|
|
||||||
|
#define PLLE_RESETB_ADDR (ESUB_CLK_BASE_ADDR + 0x00000C58) |
||||||
|
#define PLLE_RESETB_I_PLL_RESETB_PLLE_MASK 0x00010000 |
||||||
|
#define PLLE_POST_RESETB_I_POST_RESETB_PLLE_MASK 0x00000001 |
||||||
|
|
||||||
|
#define PLL_LOCK_ADDR (ESUB_CLK_BASE_ADDR + 0x00000C38) |
||||||
|
#define PLL_LOCK_PLL_LOCK_PLLE_MASK 0x00000001 |
||||||
|
|
||||||
|
#define ESW_SYS_DIV_ADDR (ESUB_CLK_BASE_ADDR + 0x00000A04) |
||||||
|
#define ESW_SYS_DIV_PLL_SELECT_MASK 0x00000300 |
||||||
|
#define ESW_SYS_DIV_DIV_MASK 0x0000001C |
||||||
|
#define ESW_SYS_DIV_PLL_VAR_208M_CLK_SELECT 0x00000100 |
||||||
|
#define ESW_SYS_DIV_DIV_SELECT 0x4 |
||||||
|
#define ESW_SYS_DIV_TRIGGER_MASK 0x00000001 |
||||||
|
|
||||||
|
#define ESUB_AXI_DIV_DEBUG_ADDR (ESUB_CLK_BASE_ADDR + 0x00000E04) |
||||||
|
#define ESUB_AXI_DIV_DEBUG_PLL_SELECT_MASK 0x0000001C |
||||||
|
#define ESUB_AXI_DIV_DEBUG_PLL_SELECT_OVERRIDE_MASK 0x00000040 |
||||||
|
#define ESUB_AXI_DIV_DEBUG_PLL_VAR_208M_CLK_SELECT 0x0 |
||||||
|
#define ESUB_AXI_DIV_DEBUG_TRIGGER_MASK 0x00000001 |
||||||
|
|
||||||
|
#define PLL_MAX_RETRY 100 |
||||||
|
|
||||||
|
/* Enable appropriate clocks for Ethernet */ |
||||||
|
int clk_eth_enable(void) |
||||||
|
{ |
||||||
|
int rc = -1; |
||||||
|
int retry_count = 0; |
||||||
|
rc = clk_get_and_enable("esub_ccu_clk"); |
||||||
|
|
||||||
|
/* Enable Access to CCU registers */ |
||||||
|
writel((1 | WR_ACCESS_PASSWORD), WR_ACCESS_ADDR); |
||||||
|
|
||||||
|
writel(readl(PLLE_POST_RESETB_ADDR) & |
||||||
|
~PLLE_POST_RESETB_I_POST_RESETB_PLLE_MASK, |
||||||
|
PLLE_POST_RESETB_ADDR); |
||||||
|
|
||||||
|
/* Take PLL out of reset and put into normal mode */ |
||||||
|
writel(readl(PLLE_RESETB_ADDR) | PLLE_RESETB_I_PLL_RESETB_PLLE_MASK, |
||||||
|
PLLE_RESETB_ADDR); |
||||||
|
|
||||||
|
/* Wait for PLL lock */ |
||||||
|
rc = -1; |
||||||
|
while (retry_count < PLL_MAX_RETRY) { |
||||||
|
udelay(100); |
||||||
|
if (readl(PLL_LOCK_ADDR) & PLL_LOCK_PLL_LOCK_PLLE_MASK) { |
||||||
|
rc = 0; |
||||||
|
break; |
||||||
|
} |
||||||
|
retry_count++; |
||||||
|
} |
||||||
|
|
||||||
|
if (rc == -1) { |
||||||
|
printf("%s: ETH-PLL lock timeout, Ethernet is not enabled!\n", |
||||||
|
__func__); |
||||||
|
return -1; |
||||||
|
} |
||||||
|
|
||||||
|
writel(readl(PLLE_POST_RESETB_ADDR) | |
||||||
|
PLLE_POST_RESETB_I_POST_RESETB_PLLE_MASK, |
||||||
|
PLLE_POST_RESETB_ADDR); |
||||||
|
|
||||||
|
/* Switch esw_sys_clk to use 104MHz(208MHz/2) clock */ |
||||||
|
writel((readl(ESW_SYS_DIV_ADDR) & |
||||||
|
~(ESW_SYS_DIV_PLL_SELECT_MASK | ESW_SYS_DIV_DIV_MASK)) | |
||||||
|
ESW_SYS_DIV_PLL_VAR_208M_CLK_SELECT | ESW_SYS_DIV_DIV_SELECT, |
||||||
|
ESW_SYS_DIV_ADDR); |
||||||
|
|
||||||
|
writel(readl(ESW_SYS_DIV_ADDR) | ESW_SYS_DIV_TRIGGER_MASK, |
||||||
|
ESW_SYS_DIV_ADDR); |
||||||
|
|
||||||
|
/* Wait for trigger complete */ |
||||||
|
rc = -1; |
||||||
|
retry_count = 0; |
||||||
|
while (retry_count < PLL_MAX_RETRY) { |
||||||
|
udelay(100); |
||||||
|
if (!(readl(ESW_SYS_DIV_ADDR) & ESW_SYS_DIV_TRIGGER_MASK)) { |
||||||
|
rc = 0; |
||||||
|
break; |
||||||
|
} |
||||||
|
retry_count++; |
||||||
|
} |
||||||
|
|
||||||
|
if (rc == -1) { |
||||||
|
printf("%s: SYS CLK Trigger timeout, Ethernet is not enabled!\n", |
||||||
|
__func__); |
||||||
|
return -1; |
||||||
|
} |
||||||
|
|
||||||
|
/* switch Esub AXI clock to 208MHz */ |
||||||
|
writel((readl(ESUB_AXI_DIV_DEBUG_ADDR) & |
||||||
|
~(ESUB_AXI_DIV_DEBUG_PLL_SELECT_MASK | |
||||||
|
ESUB_AXI_DIV_DEBUG_PLL_SELECT_OVERRIDE_MASK | |
||||||
|
ESUB_AXI_DIV_DEBUG_TRIGGER_MASK)) | |
||||||
|
ESUB_AXI_DIV_DEBUG_PLL_VAR_208M_CLK_SELECT | |
||||||
|
ESUB_AXI_DIV_DEBUG_PLL_SELECT_OVERRIDE_MASK, |
||||||
|
ESUB_AXI_DIV_DEBUG_ADDR); |
||||||
|
|
||||||
|
writel(readl(ESUB_AXI_DIV_DEBUG_ADDR) | |
||||||
|
ESUB_AXI_DIV_DEBUG_TRIGGER_MASK, |
||||||
|
ESUB_AXI_DIV_DEBUG_ADDR); |
||||||
|
|
||||||
|
/* Wait for trigger complete */ |
||||||
|
rc = -1; |
||||||
|
retry_count = 0; |
||||||
|
while (retry_count < PLL_MAX_RETRY) { |
||||||
|
udelay(100); |
||||||
|
if (!(readl(ESUB_AXI_DIV_DEBUG_ADDR) & |
||||||
|
ESUB_AXI_DIV_DEBUG_TRIGGER_MASK)) { |
||||||
|
rc = 0; |
||||||
|
break; |
||||||
|
} |
||||||
|
retry_count++; |
||||||
|
} |
||||||
|
|
||||||
|
if (rc == -1) { |
||||||
|
printf("%s: AXI CLK Trigger timeout, Ethernet is not enabled!\n", |
||||||
|
__func__); |
||||||
|
return -1; |
||||||
|
} |
||||||
|
|
||||||
|
/* Disable Access to CCU registers */ |
||||||
|
writel(WR_ACCESS_PASSWORD, WR_ACCESS_ADDR); |
||||||
|
|
||||||
|
return rc; |
||||||
|
} |
@ -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; |
||||||
|
} |
@ -0,0 +1,27 @@ |
|||||||
|
/*
|
||||||
|
* Copyright 2014 Broadcom Corporation. |
||||||
|
* |
||||||
|
* SPDX-License-Identifier: GPL-2.0+ |
||||||
|
*/ |
||||||
|
|
||||||
|
#include <common.h> |
||||||
|
#include <asm/errno.h> |
||||||
|
#include <asm/arch/sysmap.h> |
||||||
|
#include "clk-core.h" |
||||||
|
|
||||||
|
/* Enable appropriate clocks for the USB OTG port */ |
||||||
|
int clk_usb_otg_enable(void *base) |
||||||
|
{ |
||||||
|
char *ahbstr; |
||||||
|
|
||||||
|
switch ((u32) base) { |
||||||
|
case HSOTG_BASE_ADDR: |
||||||
|
ahbstr = "usb_otg_ahb_clk"; |
||||||
|
break; |
||||||
|
default: |
||||||
|
printf("%s: base 0x%p not found\n", __func__, base); |
||||||
|
return -EINVAL; |
||||||
|
} |
||||||
|
|
||||||
|
return clk_get_and_enable(ahbstr); |
||||||
|
} |
@ -0,0 +1,26 @@ |
|||||||
|
/* |
||||||
|
* Copyright 2013 Broadcom Corporation. |
||||||
|
* |
||||||
|
* SPDX-License-Identifier: GPL-2.0+ |
||||||
|
*/ |
||||||
|
|
||||||
|
.globl reset_cpu
|
||||||
|
reset_cpu: |
||||||
|
ldr r1, =0x35001f00 |
||||||
|
ldr r2, [r1] |
||||||
|
ldr r4, =0x80000000 |
||||||
|
and r4, r2, r4 |
||||||
|
ldr r3, =0xA5A500 |
||||||
|
orr r4, r4, r3 |
||||||
|
orr r4, r4, #0x1 |
||||||
|
|
||||||
|
str r4, [r1] |
||||||
|
|
||||||
|
ldr r1, =0x35001f04 |
||||||
|
ldr r2, [r1] |
||||||
|
ldr r4, =0x80000000 |
||||||
|
and r4, r2, r4 |
||||||
|
str r4, [r1] |
||||||
|
|
||||||
|
_loop_forever: |
||||||
|
b _loop_forever |
@ -0,0 +1,15 @@ |
|||||||
|
/*
|
||||||
|
* Copyright 2013 Broadcom Corporation. |
||||||
|
* |
||||||
|
* SPDX-License-Identifier: GPL-2.0+ |
||||||
|
*/ |
||||||
|
|
||||||
|
#ifndef __ARCH_BCM235XX_GPIO_H |
||||||
|
#define __ARCH_BCM235XX_GPIO_H |
||||||
|
|
||||||
|
/*
|
||||||
|
* Empty file - cmd_gpio.c requires this. The implementation |
||||||
|
* is in drivers/gpio/kona_gpio.c instead of inlined here. |
||||||
|
*/ |
||||||
|
|
||||||
|
#endif |
@ -0,0 +1,31 @@ |
|||||||
|
/*
|
||||||
|
* Copyright 2013 Broadcom Corporation. |
||||||
|
* |
||||||
|
* SPDX-License-Identifier: GPL-2.0+ |
||||||
|
*/ |
||||||
|
|
||||||
|
#ifndef __ARCH_BCM235XX_SYSMAP_H |
||||||
|
|
||||||
|
#define BSC1_BASE_ADDR 0x3e016000 |
||||||
|
#define BSC2_BASE_ADDR 0x3e017000 |
||||||
|
#define BSC3_BASE_ADDR 0x3e018000 |
||||||
|
#define GPIO2_BASE_ADDR 0x35003000 |
||||||
|
#define HSOTG_BASE_ADDR 0x3f120000 |
||||||
|
#define HSOTG_CTRL_BASE_ADDR 0x3f130000 |
||||||
|
#define KONA_MST_CLK_BASE_ADDR 0x3f001000 |
||||||
|
#define KONA_SLV_CLK_BASE_ADDR 0x3e011000 |
||||||
|
#define PMU_BSC_BASE_ADDR 0x3500d000 |
||||||
|
#define SDIO1_BASE_ADDR 0x3f180000 |
||||||
|
#define SDIO2_BASE_ADDR 0x3f190000 |
||||||
|
#define SDIO3_BASE_ADDR 0x3f1a0000 |
||||||
|
#define SDIO4_BASE_ADDR 0x3f1b0000 |
||||||
|
#define TIMER_BASE_ADDR 0x3e00d000 |
||||||
|
|
||||||
|
#define HSOTG_DCTL_OFFSET 0x00000804 |
||||||
|
#define HSOTG_DCTL_SFTDISCON_MASK 0x00000002 |
||||||
|
|
||||||
|
#define HSOTG_CTRL_PHY_P1CTL_OFFSET 0x00000008 |
||||||
|
#define HSOTG_CTRL_PHY_P1CTL_SOFT_RESET_MASK 0x00000002 |
||||||
|
#define HSOTG_CTRL_PHY_P1CTL_NON_DRIVING_MASK 0x00000001 |
||||||
|
|
||||||
|
#endif |
@ -0,0 +1,15 @@ |
|||||||
|
if TARGET_BCM23550_W1D |
||||||
|
|
||||||
|
config SYS_BOARD |
||||||
|
default "bcm23550_w1d" |
||||||
|
|
||||||
|
config SYS_VENDOR |
||||||
|
default "broadcom" |
||||||
|
|
||||||
|
config SYS_SOC |
||||||
|
default "bcm235xx" |
||||||
|
|
||||||
|
config SYS_CONFIG_NAME |
||||||
|
default "bcm23550_w1d" |
||||||
|
|
||||||
|
endif |
@ -0,0 +1,6 @@ |
|||||||
|
BCM23550_W1D BOARD |
||||||
|
M: Steve Rae <srae@broadcom.com> |
||||||
|
S: Maintained |
||||||
|
F: board/broadcom/bcm23550_w1d/ |
||||||
|
F: include/configs/bcm23550_w1d.h |
||||||
|
F: configs/bcm23550_w1d_defconfig |
@ -0,0 +1,7 @@ |
|||||||
|
#
|
||||||
|
# Copyright 2013 Broadcom Corporation.
|
||||||
|
#
|
||||||
|
# SPDX-License-Identifier: GPL-2.0+
|
||||||
|
#
|
||||||
|
|
||||||
|
obj-y += bcm23550_w1d.o
|
@ -0,0 +1,120 @@ |
|||||||
|
/*
|
||||||
|
* Copyright 2013 Broadcom Corporation. |
||||||
|
* |
||||||
|
* SPDX-License-Identifier: GPL-2.0+ |
||||||
|
*/ |
||||||
|
|
||||||
|
#include <common.h> |
||||||
|
#include <asm/io.h> |
||||||
|
#include <asm/mach-types.h> |
||||||
|
#include <mmc.h> |
||||||
|
#include <asm/kona-common/kona_sdhci.h> |
||||||
|
#include <asm/kona-common/clk.h> |
||||||
|
#include <asm/arch/sysmap.h> |
||||||
|
|
||||||
|
#include <usb.h> |
||||||
|
#include <usb/dwc2_udc.h> |
||||||
|
#include <g_dnl.h> |
||||||
|
|
||||||
|
#define SECWATCHDOG_SDOGCR_OFFSET 0x00000000 |
||||||
|
#define SECWATCHDOG_SDOGCR_EN_SHIFT 27 |
||||||
|
#define SECWATCHDOG_SDOGCR_SRSTEN_SHIFT 26 |
||||||
|
#define SECWATCHDOG_SDOGCR_CLKS_SHIFT 20 |
||||||
|
#define SECWATCHDOG_SDOGCR_LD_SHIFT 0 |
||||||
|
|
||||||
|
#ifndef CONFIG_USB_SERIALNO |
||||||
|
#define CONFIG_USB_SERIALNO "1234567890" |
||||||
|
#endif |
||||||
|
|
||||||
|
DECLARE_GLOBAL_DATA_PTR; |
||||||
|
|
||||||
|
/*
|
||||||
|
* board_init - early hardware init |
||||||
|
*/ |
||||||
|
int board_init(void) |
||||||
|
{ |
||||||
|
printf("Relocation Offset is: %08lx\n", gd->reloc_off); |
||||||
|
|
||||||
|
/* adress of boot parameters */ |
||||||
|
gd->bd->bi_boot_params = CONFIG_SYS_SDRAM_BASE + 0x100; |
||||||
|
|
||||||
|
clk_init(); |
||||||
|
|
||||||
|
return 0; |
||||||
|
} |
||||||
|
|
||||||
|
/*
|
||||||
|
* misc_init_r - miscellaneous platform dependent initializations |
||||||
|
*/ |
||||||
|
int misc_init_r(void) |
||||||
|
{ |
||||||
|
return 0; |
||||||
|
} |
||||||
|
|
||||||
|
/*
|
||||||
|
* dram_init - sets uboots idea of sdram size |
||||||
|
*/ |
||||||
|
int dram_init(void) |
||||||
|
{ |
||||||
|
gd->ram_size = get_ram_size((long *)CONFIG_SYS_SDRAM_BASE, |
||||||
|
CONFIG_SYS_SDRAM_SIZE); |
||||||
|
return 0; |
||||||
|
} |
||||||
|
|
||||||
|
/* This is called after dram_init() so use get_ram_size result */ |
||||||
|
void dram_init_banksize(void) |
||||||
|
{ |
||||||
|
gd->bd->bi_dram[0].start = CONFIG_SYS_SDRAM_BASE; |
||||||
|
gd->bd->bi_dram[0].size = gd->ram_size; |
||||||
|
} |
||||||
|
|
||||||
|
#ifdef CONFIG_KONA_SDHCI |
||||||
|
/*
|
||||||
|
* mmc_init - Initializes mmc |
||||||
|
*/ |
||||||
|
int board_mmc_init(bd_t *bis) |
||||||
|
{ |
||||||
|
int ret = 0; |
||||||
|
|
||||||
|
/* Register eMMC - SDIO2 */ |
||||||
|
ret = kona_sdhci_init(1, 400000, 0); |
||||||
|
if (ret) |
||||||
|
return ret; |
||||||
|
|
||||||
|
/* Register SD Card - SDIO4 kona_mmc_init assumes 0 based index */ |
||||||
|
ret = kona_sdhci_init(3, 400000, 0); |
||||||
|
return ret; |
||||||
|
} |
||||||
|
#endif |
||||||
|
|
||||||
|
#ifdef CONFIG_USB_GADGET |
||||||
|
static struct dwc2_plat_otg_data bcm_otg_data = { |
||||||
|
.regs_otg = HSOTG_BASE_ADDR |
||||||
|
}; |
||||||
|
|
||||||
|
int board_usb_init(int index, enum usb_init_type init) |
||||||
|
{ |
||||||
|
debug("%s: performing dwc2_udc_probe\n", __func__); |
||||||
|
return dwc2_udc_probe(&bcm_otg_data); |
||||||
|
} |
||||||
|
|
||||||
|
int g_dnl_bind_fixup(struct usb_device_descriptor *dev, const char *name) |
||||||
|
{ |
||||||
|
debug("%s\n", __func__); |
||||||
|
if (!getenv("serial#")) |
||||||
|
g_dnl_set_serialnumber(CONFIG_USB_SERIALNO); |
||||||
|
return 0; |
||||||
|
} |
||||||
|
|
||||||
|
int g_dnl_get_board_bcd_device_number(int gcnum) |
||||||
|
{ |
||||||
|
debug("%s\n", __func__); |
||||||
|
return 1; |
||||||
|
} |
||||||
|
|
||||||
|
int board_usb_cleanup(int index, enum usb_init_type init) |
||||||
|
{ |
||||||
|
debug("%s\n", __func__); |
||||||
|
return 0; |
||||||
|
} |
||||||
|
#endif |
@ -0,0 +1,24 @@ |
|||||||
|
CONFIG_ARM=y |
||||||
|
CONFIG_TARGET_BCM23550_W1D=y |
||||||
|
CONFIG_HUSH_PARSER=y |
||||||
|
CONFIG_CMD_BOOTZ=y |
||||||
|
# CONFIG_CMD_IMLS is not set |
||||||
|
CONFIG_CMD_ASKENV=y |
||||||
|
# CONFIG_CMD_FLASH is not set |
||||||
|
CONFIG_CMD_MMC=y |
||||||
|
CONFIG_CMD_I2C=y |
||||||
|
CONFIG_CMD_GPIO=y |
||||||
|
# CONFIG_CMD_SETEXPR is not set |
||||||
|
# CONFIG_CMD_NET is not set |
||||||
|
# CONFIG_CMD_NFS is not set |
||||||
|
CONFIG_CMD_CACHE=y |
||||||
|
CONFIG_CMD_FAT=y |
||||||
|
CONFIG_SYS_NS16550=y |
||||||
|
CONFIG_USB=y |
||||||
|
CONFIG_USB_GADGET=y |
||||||
|
CONFIG_USB_GADGET_DWC2_OTG=y |
||||||
|
CONFIG_USB_GADGET_DOWNLOAD=y |
||||||
|
CONFIG_G_DNL_MANUFACTURER="Broadcom Corporation" |
||||||
|
CONFIG_G_DNL_VENDOR_NUM=0x18d1 |
||||||
|
CONFIG_G_DNL_PRODUCT_NUM=0x0d02 |
||||||
|
CONFIG_OF_LIBFDT=y |
@ -0,0 +1,148 @@ |
|||||||
|
/*
|
||||||
|
* Copyright 2013 Broadcom Corporation. |
||||||
|
* |
||||||
|
* SPDX-License-Identifier: GPL-2.0+ |
||||||
|
*/ |
||||||
|
|
||||||
|
#ifndef __BCM23550_W1D_H |
||||||
|
#define __BCM23550_W1D_H |
||||||
|
|
||||||
|
#include <linux/sizes.h> |
||||||
|
#include <asm/arch/sysmap.h> |
||||||
|
|
||||||
|
/* CPU, chip, mach, etc */ |
||||||
|
#define CONFIG_KONA |
||||||
|
#define CONFIG_SKIP_LOWLEVEL_INIT |
||||||
|
#define CONFIG_KONA_RESET_S |
||||||
|
|
||||||
|
/*
|
||||||
|
* Memory configuration |
||||||
|
*/ |
||||||
|
#define CONFIG_SYS_TEXT_BASE 0x9f000000 |
||||||
|
|
||||||
|
#define CONFIG_SYS_SDRAM_BASE 0x80000000 |
||||||
|
#define CONFIG_SYS_SDRAM_SIZE 0x20000000 |
||||||
|
#define CONFIG_NR_DRAM_BANKS 1 |
||||||
|
|
||||||
|
#define CONFIG_SYS_MALLOC_LEN SZ_4M /* see armv7/start.S. */ |
||||||
|
#define CONFIG_STACKSIZE SZ_256K |
||||||
|
|
||||||
|
/* GPIO Driver */ |
||||||
|
#define CONFIG_KONA_GPIO |
||||||
|
|
||||||
|
/* MMC/SD Driver */ |
||||||
|
#define CONFIG_SDHCI |
||||||
|
#define CONFIG_MMC_SDMA |
||||||
|
#define CONFIG_KONA_SDHCI |
||||||
|
#define CONFIG_MMC |
||||||
|
#define CONFIG_GENERIC_MMC |
||||||
|
|
||||||
|
#define CONFIG_SYS_SDIO_BASE0 SDIO1_BASE_ADDR |
||||||
|
#define CONFIG_SYS_SDIO_BASE1 SDIO2_BASE_ADDR |
||||||
|
#define CONFIG_SYS_SDIO_BASE2 SDIO3_BASE_ADDR |
||||||
|
#define CONFIG_SYS_SDIO_BASE3 SDIO4_BASE_ADDR |
||||||
|
#define CONFIG_SYS_SDIO0_MAX_CLK 48000000 |
||||||
|
#define CONFIG_SYS_SDIO1_MAX_CLK 48000000 |
||||||
|
#define CONFIG_SYS_SDIO2_MAX_CLK 48000000 |
||||||
|
#define CONFIG_SYS_SDIO3_MAX_CLK 48000000 |
||||||
|
#define CONFIG_SYS_SDIO0 "sdio1" |
||||||
|
#define CONFIG_SYS_SDIO1 "sdio2" |
||||||
|
#define CONFIG_SYS_SDIO2 "sdio3" |
||||||
|
#define CONFIG_SYS_SDIO3 "sdio4" |
||||||
|
|
||||||
|
/* I2C Driver */ |
||||||
|
#define CONFIG_SYS_I2C |
||||||
|
#define CONFIG_SYS_I2C_KONA |
||||||
|
#define CONFIG_SYS_SPD_BUS_NUM 3 /* Start with PMU bus */ |
||||||
|
#define CONFIG_SYS_MAX_I2C_BUS 4 |
||||||
|
#define CONFIG_SYS_I2C_BASE0 BSC1_BASE_ADDR |
||||||
|
#define CONFIG_SYS_I2C_BASE1 BSC2_BASE_ADDR |
||||||
|
#define CONFIG_SYS_I2C_BASE2 BSC3_BASE_ADDR |
||||||
|
#define CONFIG_SYS_I2C_BASE3 PMU_BSC_BASE_ADDR |
||||||
|
|
||||||
|
/* Timer Driver */ |
||||||
|
#define CONFIG_SYS_TIMER_RATE 32000 |
||||||
|
#define CONFIG_SYS_TIMER_COUNTER (TIMER_BASE_ADDR + 4) /* STCLO offset */ |
||||||
|
|
||||||
|
/* Init functions */ |
||||||
|
#define CONFIG_MISC_INIT_R /* board's misc_init_r function */ |
||||||
|
|
||||||
|
/* Some commands use this as the default load address */ |
||||||
|
#define CONFIG_SYS_LOAD_ADDR CONFIG_SYS_SDRAM_BASE |
||||||
|
|
||||||
|
/* No mtest functions as recommended */ |
||||||
|
|
||||||
|
/*
|
||||||
|
* This is the initial SP which is used only briefly for relocating the u-boot |
||||||
|
* image to the top of SDRAM. After relocation u-boot moves the stack to the |
||||||
|
* proper place. |
||||||
|
*/ |
||||||
|
#define CONFIG_SYS_INIT_SP_ADDR CONFIG_SYS_TEXT_BASE |
||||||
|
|
||||||
|
/* Serial Info */ |
||||||
|
#define CONFIG_SYS_NS16550_SERIAL |
||||||
|
/* Post pad 3 bytes after each reg addr */ |
||||||
|
#define CONFIG_SYS_NS16550_REG_SIZE (-4) |
||||||
|
#define CONFIG_SYS_NS16550_CLK 13000000 |
||||||
|
#define CONFIG_CONS_INDEX 1 |
||||||
|
#define CONFIG_SYS_NS16550_COM1 0x3e000000 |
||||||
|
|
||||||
|
#define CONFIG_BAUDRATE 115200 |
||||||
|
|
||||||
|
/* must fit into GPT:u-boot-env partition */ |
||||||
|
#define CONFIG_ENV_IS_IN_MMC |
||||||
|
#define CONFIG_SYS_MMC_ENV_DEV 0 |
||||||
|
#define CONFIG_ENV_OFFSET (0x00011a00 * 512) |
||||||
|
#define CONFIG_ENV_SIZE (8 * 512) |
||||||
|
|
||||||
|
#define CONFIG_SYS_NO_FLASH /* Not using NAND/NOR unmanaged flash */ |
||||||
|
|
||||||
|
/* console configuration */ |
||||||
|
#define CONFIG_SYS_CBSIZE 1024 /* Console buffer size */ |
||||||
|
#define CONFIG_SYS_PBSIZE (CONFIG_SYS_CBSIZE + \ |
||||||
|
sizeof(CONFIG_SYS_PROMPT) + 16) /* Printbuffer size */ |
||||||
|
#define CONFIG_SYS_MAXARGS 64 |
||||||
|
#define CONFIG_SYS_BARGSIZE CONFIG_SYS_CBSIZE |
||||||
|
|
||||||
|
/*
|
||||||
|
* One partition type must be defined for part.c |
||||||
|
* This is necessary for the fatls command to work on an SD card |
||||||
|
* for example. |
||||||
|
*/ |
||||||
|
#define CONFIG_DOS_PARTITION |
||||||
|
#define CONFIG_EFI_PARTITION |
||||||
|
|
||||||
|
/* version string, parser, etc */ |
||||||
|
#define CONFIG_VERSION_VARIABLE |
||||||
|
#define CONFIG_AUTO_COMPLETE |
||||||
|
#define CONFIG_CMDLINE_EDITING |
||||||
|
#define CONFIG_SYS_LONGHELP |
||||||
|
|
||||||
|
#define CONFIG_CRC32_VERIFY |
||||||
|
#define CONFIG_MX_CYCLIC |
||||||
|
|
||||||
|
/* Initial upstream - boot to cmd prompt only */ |
||||||
|
#define CONFIG_BOOTCOMMAND "" |
||||||
|
|
||||||
|
/* Commands */ |
||||||
|
#define CONFIG_FAT_WRITE |
||||||
|
|
||||||
|
/* Fastboot and USB OTG */ |
||||||
|
#define CONFIG_USB_FUNCTION_FASTBOOT |
||||||
|
#define CONFIG_CMD_FASTBOOT |
||||||
|
#define CONFIG_FASTBOOT_FLASH |
||||||
|
#define CONFIG_FASTBOOT_FLASH_MMC_DEV 0 |
||||||
|
#define CONFIG_SYS_CACHELINE_SIZE 64 |
||||||
|
#define CONFIG_FASTBOOT_BUF_SIZE 0x1d000000 |
||||||
|
#define CONFIG_FASTBOOT_BUF_ADDR CONFIG_SYS_SDRAM_BASE |
||||||
|
#undef CONFIG_USB_GADGET_VBUS_DRAW |
||||||
|
#define CONFIG_USB_GADGET_VBUS_DRAW 0 |
||||||
|
#define CONFIG_USB_GADGET_DWC2_PHY_8_BIT |
||||||
|
#define CONFIG_USB_GADGET_BCM_UDC_OTG_PHY |
||||||
|
#define CONFIG_USBID_ADDR 0x34052c46 |
||||||
|
|
||||||
|
#define CONFIG_SYS_ICACHE_OFF |
||||||
|
#define CONFIG_SYS_DCACHE_OFF |
||||||
|
#define CONFIG_SYS_L2CACHE_OFF |
||||||
|
|
||||||
|
#endif /* __BCM23550_W1D_H */ |
Loading…
Reference in new issue