Commit b12151ca authored by Alex Elder's avatar Alex Elder Committed by Mike Turquette

clk: bcm281xx: initialize CCU structures statically

We know up front how many CCU's we'll support, so there's no need to
allocate their data structures dynamically.  Define a macro
KONA_CCU_COMMON() to simplify the initialization of many of the
fields in a ccu_data structure.  Pass the address of a statically
defined CCU structure to kona_dt_ccu_setup() rather than having that
function allocate one.

We also know at build time how many clocks a given CCU will provide,
though the number of of them for each CCU is different.  Record the
number of clocks we need in the CCU's clk_onecell_data struct
(which is used when we register the CCU with the common clock code
as a clock provider).  Rename that struct field "clk_data" (because
"data" alone gets a little confusing).

Use the known clock count to move the allocation of each CCU's
clocks array into ccu_clks_setup() rather than having each CCU's
setup callback function do it.

(The real motivation behind all of this is that we'll be doing some
static initialization of some additional CCU-specific data soon.)
Signed-off-by: default avatarAlex Elder <elder@linaro.org>
Signed-off-by: default avatarMike Turquette <mturquette@linaro.org>
parent 9d3d87c7
...@@ -15,6 +15,9 @@ ...@@ -15,6 +15,9 @@
#include "clk-kona.h" #include "clk-kona.h"
#include "dt-bindings/clock/bcm281xx.h" #include "dt-bindings/clock/bcm281xx.h"
#define BCM281XX_CCU_COMMON(_name, _ucase_name) \
KONA_CCU_COMMON(BCM281XX, _name, _ucase_name)
/* /*
* These are the bcm281xx CCU device tree "compatible" strings. * These are the bcm281xx CCU device tree "compatible" strings.
* We're stuck with using "bcm11351" in the string because wild * We're stuck with using "bcm11351" in the string because wild
...@@ -27,7 +30,7 @@ ...@@ -27,7 +30,7 @@
#define BCM281XX_DT_MASTER_CCU_COMPAT "brcm,bcm11351-master-ccu" #define BCM281XX_DT_MASTER_CCU_COMPAT "brcm,bcm11351-master-ccu"
#define BCM281XX_DT_SLAVE_CCU_COMPAT "brcm,bcm11351-slave-ccu" #define BCM281XX_DT_SLAVE_CCU_COMPAT "brcm,bcm11351-slave-ccu"
/* Root CCU clocks */ /* Root CCU */
static struct peri_clk_data frac_1m_data = { static struct peri_clk_data frac_1m_data = {
.gate = HW_SW_GATE(0x214, 16, 0, 1), .gate = HW_SW_GATE(0x214, 16, 0, 1),
...@@ -36,7 +39,11 @@ static struct peri_clk_data frac_1m_data = { ...@@ -36,7 +39,11 @@ static struct peri_clk_data frac_1m_data = {
.clocks = CLOCKS("ref_crystal"), .clocks = CLOCKS("ref_crystal"),
}; };
/* AON CCU clocks */ static struct ccu_data root_ccu_data = {
BCM281XX_CCU_COMMON(root, ROOT),
};
/* AON CCU */
static struct peri_clk_data hub_timer_data = { static struct peri_clk_data hub_timer_data = {
.gate = HW_SW_GATE(0x0414, 16, 0, 1), .gate = HW_SW_GATE(0x0414, 16, 0, 1),
...@@ -65,7 +72,11 @@ static struct peri_clk_data pmu_bsc_var_data = { ...@@ -65,7 +72,11 @@ static struct peri_clk_data pmu_bsc_var_data = {
.trig = TRIGGER(0x0a40, 2), .trig = TRIGGER(0x0a40, 2),
}; };
/* Hub CCU clocks */ static struct ccu_data aon_ccu_data = {
BCM281XX_CCU_COMMON(aon, AON),
};
/* Hub CCU */
static struct peri_clk_data tmon_1m_data = { static struct peri_clk_data tmon_1m_data = {
.gate = HW_SW_GATE(0x04a4, 18, 2, 3), .gate = HW_SW_GATE(0x04a4, 18, 2, 3),
...@@ -75,7 +86,11 @@ static struct peri_clk_data tmon_1m_data = { ...@@ -75,7 +86,11 @@ static struct peri_clk_data tmon_1m_data = {
.trig = TRIGGER(0x0e84, 1), .trig = TRIGGER(0x0e84, 1),
}; };
/* Master CCU clocks */ static struct ccu_data hub_ccu_data = {
BCM281XX_CCU_COMMON(hub, HUB),
};
/* Master CCU */
static struct peri_clk_data sdio1_data = { static struct peri_clk_data sdio1_data = {
.gate = HW_SW_GATE(0x0358, 18, 2, 3), .gate = HW_SW_GATE(0x0358, 18, 2, 3),
...@@ -158,7 +173,11 @@ static struct peri_clk_data hsic2_12m_data = { ...@@ -158,7 +173,11 @@ static struct peri_clk_data hsic2_12m_data = {
.trig = TRIGGER(0x0afc, 5), .trig = TRIGGER(0x0afc, 5),
}; };
/* Slave CCU clocks */ static struct ccu_data master_ccu_data = {
BCM281XX_CCU_COMMON(master, MASTER),
};
/* Slave CCU */
static struct peri_clk_data uartb_data = { static struct peri_clk_data uartb_data = {
.gate = HW_SW_GATE(0x0400, 18, 2, 3), .gate = HW_SW_GATE(0x0400, 18, 2, 3),
...@@ -266,6 +285,10 @@ static struct peri_clk_data pwm_data = { ...@@ -266,6 +285,10 @@ static struct peri_clk_data pwm_data = {
.trig = TRIGGER(0x0afc, 15), .trig = TRIGGER(0x0afc, 15),
}; };
static struct ccu_data slave_ccu_data = {
BCM281XX_CCU_COMMON(slave, SLAVE),
};
/* /*
* CCU setup routines * CCU setup routines
* *
...@@ -277,107 +300,52 @@ static struct peri_clk_data pwm_data = { ...@@ -277,107 +300,52 @@ static struct peri_clk_data pwm_data = {
*/ */
static int __init bcm281xx_root_ccu_clks_setup(struct ccu_data *ccu) static int __init bcm281xx_root_ccu_clks_setup(struct ccu_data *ccu)
{ {
struct clk **clks; PERI_CLK_SETUP(ccu, BCM281XX_ROOT_CCU_FRAC_1M, frac_1m);
size_t count = BCM281XX_ROOT_CCU_CLOCK_COUNT;
clks = kzalloc(count * sizeof(*clks), GFP_KERNEL);
if (!clks) {
pr_err("%s: failed to allocate root clocks\n", __func__);
return -ENOMEM;
}
ccu->data.clks = clks;
ccu->data.clk_num = count;
PERI_CLK_SETUP(clks, ccu, BCM281XX_ROOT_CCU_FRAC_1M, frac_1m);
return 0; return 0;
} }
static int __init bcm281xx_aon_ccu_clks_setup(struct ccu_data *ccu) static int __init bcm281xx_aon_ccu_clks_setup(struct ccu_data *ccu)
{ {
struct clk **clks; PERI_CLK_SETUP(ccu, BCM281XX_AON_CCU_HUB_TIMER, hub_timer);
size_t count = BCM281XX_AON_CCU_CLOCK_COUNT; PERI_CLK_SETUP(ccu, BCM281XX_AON_CCU_PMU_BSC, pmu_bsc);
PERI_CLK_SETUP(ccu, BCM281XX_AON_CCU_PMU_BSC_VAR, pmu_bsc_var);
clks = kzalloc(count * sizeof(*clks), GFP_KERNEL);
if (!clks) {
pr_err("%s: failed to allocate aon clocks\n", __func__);
return -ENOMEM;
}
ccu->data.clks = clks;
ccu->data.clk_num = count;
PERI_CLK_SETUP(clks, ccu, BCM281XX_AON_CCU_HUB_TIMER, hub_timer);
PERI_CLK_SETUP(clks, ccu, BCM281XX_AON_CCU_PMU_BSC, pmu_bsc);
PERI_CLK_SETUP(clks, ccu, BCM281XX_AON_CCU_PMU_BSC_VAR, pmu_bsc_var);
return 0; return 0;
} }
static int __init bcm281xx_hub_ccu_clks_setup(struct ccu_data *ccu) static int __init bcm281xx_hub_ccu_clks_setup(struct ccu_data *ccu)
{ {
struct clk **clks; PERI_CLK_SETUP(ccu, BCM281XX_HUB_CCU_TMON_1M, tmon_1m);
size_t count = BCM281XX_HUB_CCU_CLOCK_COUNT;
clks = kzalloc(count * sizeof(*clks), GFP_KERNEL);
if (!clks) {
pr_err("%s: failed to allocate hub clocks\n", __func__);
return -ENOMEM;
}
ccu->data.clks = clks;
ccu->data.clk_num = count;
PERI_CLK_SETUP(clks, ccu, BCM281XX_HUB_CCU_TMON_1M, tmon_1m);
return 0; return 0;
} }
static int __init bcm281xx_master_ccu_clks_setup(struct ccu_data *ccu) static int __init bcm281xx_master_ccu_clks_setup(struct ccu_data *ccu)
{ {
struct clk **clks; PERI_CLK_SETUP(ccu, BCM281XX_MASTER_CCU_SDIO1, sdio1);
size_t count = BCM281XX_MASTER_CCU_CLOCK_COUNT; PERI_CLK_SETUP(ccu, BCM281XX_MASTER_CCU_SDIO2, sdio2);
PERI_CLK_SETUP(ccu, BCM281XX_MASTER_CCU_SDIO3, sdio3);
clks = kzalloc(count * sizeof(*clks), GFP_KERNEL); PERI_CLK_SETUP(ccu, BCM281XX_MASTER_CCU_SDIO4, sdio4);
if (!clks) { PERI_CLK_SETUP(ccu, BCM281XX_MASTER_CCU_USB_IC, usb_ic);
pr_err("%s: failed to allocate master clocks\n", __func__); PERI_CLK_SETUP(ccu, BCM281XX_MASTER_CCU_HSIC2_48M, hsic2_48m);
return -ENOMEM; PERI_CLK_SETUP(ccu, BCM281XX_MASTER_CCU_HSIC2_12M, hsic2_12m);
}
ccu->data.clks = clks;
ccu->data.clk_num = count;
PERI_CLK_SETUP(clks, ccu, BCM281XX_MASTER_CCU_SDIO1, sdio1);
PERI_CLK_SETUP(clks, ccu, BCM281XX_MASTER_CCU_SDIO2, sdio2);
PERI_CLK_SETUP(clks, ccu, BCM281XX_MASTER_CCU_SDIO3, sdio3);
PERI_CLK_SETUP(clks, ccu, BCM281XX_MASTER_CCU_SDIO4, sdio4);
PERI_CLK_SETUP(clks, ccu, BCM281XX_MASTER_CCU_USB_IC, usb_ic);
PERI_CLK_SETUP(clks, ccu, BCM281XX_MASTER_CCU_HSIC2_48M, hsic2_48m);
PERI_CLK_SETUP(clks, ccu, BCM281XX_MASTER_CCU_HSIC2_12M, hsic2_12m);
return 0; return 0;
} }
static int __init bcm281xx_slave_ccu_clks_setup(struct ccu_data *ccu) static int __init bcm281xx_slave_ccu_clks_setup(struct ccu_data *ccu)
{ {
struct clk **clks; PERI_CLK_SETUP(ccu, BCM281XX_SLAVE_CCU_UARTB, uartb);
size_t count = BCM281XX_SLAVE_CCU_CLOCK_COUNT; PERI_CLK_SETUP(ccu, BCM281XX_SLAVE_CCU_UARTB2, uartb2);
PERI_CLK_SETUP(ccu, BCM281XX_SLAVE_CCU_UARTB3, uartb3);
clks = kzalloc(count * sizeof(*clks), GFP_KERNEL); PERI_CLK_SETUP(ccu, BCM281XX_SLAVE_CCU_UARTB4, uartb4);
if (!clks) { PERI_CLK_SETUP(ccu, BCM281XX_SLAVE_CCU_SSP0, ssp0);
pr_err("%s: failed to allocate slave clocks\n", __func__); PERI_CLK_SETUP(ccu, BCM281XX_SLAVE_CCU_SSP2, ssp2);
return -ENOMEM; PERI_CLK_SETUP(ccu, BCM281XX_SLAVE_CCU_BSC1, bsc1);
} PERI_CLK_SETUP(ccu, BCM281XX_SLAVE_CCU_BSC2, bsc2);
ccu->data.clks = clks; PERI_CLK_SETUP(ccu, BCM281XX_SLAVE_CCU_BSC3, bsc3);
ccu->data.clk_num = count; PERI_CLK_SETUP(ccu, BCM281XX_SLAVE_CCU_PWM, pwm);
PERI_CLK_SETUP(clks, ccu, BCM281XX_SLAVE_CCU_UARTB, uartb);
PERI_CLK_SETUP(clks, ccu, BCM281XX_SLAVE_CCU_UARTB2, uartb2);
PERI_CLK_SETUP(clks, ccu, BCM281XX_SLAVE_CCU_UARTB3, uartb3);
PERI_CLK_SETUP(clks, ccu, BCM281XX_SLAVE_CCU_UARTB4, uartb4);
PERI_CLK_SETUP(clks, ccu, BCM281XX_SLAVE_CCU_SSP0, ssp0);
PERI_CLK_SETUP(clks, ccu, BCM281XX_SLAVE_CCU_SSP2, ssp2);
PERI_CLK_SETUP(clks, ccu, BCM281XX_SLAVE_CCU_BSC1, bsc1);
PERI_CLK_SETUP(clks, ccu, BCM281XX_SLAVE_CCU_BSC2, bsc2);
PERI_CLK_SETUP(clks, ccu, BCM281XX_SLAVE_CCU_BSC3, bsc3);
PERI_CLK_SETUP(clks, ccu, BCM281XX_SLAVE_CCU_PWM, pwm);
return 0; return 0;
} }
...@@ -386,27 +354,29 @@ static int __init bcm281xx_slave_ccu_clks_setup(struct ccu_data *ccu) ...@@ -386,27 +354,29 @@ static int __init bcm281xx_slave_ccu_clks_setup(struct ccu_data *ccu)
static void __init kona_dt_root_ccu_setup(struct device_node *node) static void __init kona_dt_root_ccu_setup(struct device_node *node)
{ {
kona_dt_ccu_setup(node, bcm281xx_root_ccu_clks_setup); kona_dt_ccu_setup(&root_ccu_data, node, bcm281xx_root_ccu_clks_setup);
} }
static void __init kona_dt_aon_ccu_setup(struct device_node *node) static void __init kona_dt_aon_ccu_setup(struct device_node *node)
{ {
kona_dt_ccu_setup(node, bcm281xx_aon_ccu_clks_setup); kona_dt_ccu_setup(&aon_ccu_data, node, bcm281xx_aon_ccu_clks_setup);
} }
static void __init kona_dt_hub_ccu_setup(struct device_node *node) static void __init kona_dt_hub_ccu_setup(struct device_node *node)
{ {
kona_dt_ccu_setup(node, bcm281xx_hub_ccu_clks_setup); kona_dt_ccu_setup(&hub_ccu_data, node, bcm281xx_hub_ccu_clks_setup);
} }
static void __init kona_dt_master_ccu_setup(struct device_node *node) static void __init kona_dt_master_ccu_setup(struct device_node *node)
{ {
kona_dt_ccu_setup(node, bcm281xx_master_ccu_clks_setup); kona_dt_ccu_setup(&master_ccu_data, node,
bcm281xx_master_ccu_clks_setup);
} }
static void __init kona_dt_slave_ccu_setup(struct device_node *node) static void __init kona_dt_slave_ccu_setup(struct device_node *node)
{ {
kona_dt_ccu_setup(node, bcm281xx_slave_ccu_clks_setup); kona_dt_ccu_setup(&slave_ccu_data, node,
bcm281xx_slave_ccu_clks_setup);
} }
CLK_OF_DECLARE(bcm281xx_root_ccu, BCM281XX_DT_ROOT_CCU_COMPAT, CLK_OF_DECLARE(bcm281xx_root_ccu, BCM281XX_DT_ROOT_CCU_COMPAT,
......
...@@ -675,51 +675,50 @@ static void ccu_clks_teardown(struct ccu_data *ccu) ...@@ -675,51 +675,50 @@ static void ccu_clks_teardown(struct ccu_data *ccu)
{ {
u32 i; u32 i;
for (i = 0; i < ccu->data.clk_num; i++) for (i = 0; i < ccu->clk_data.clk_num; i++)
kona_clk_teardown(ccu->data.clks[i]); kona_clk_teardown(ccu->clk_data.clks[i]);
kfree(ccu->data.clks); kfree(ccu->clk_data.clks);
} }
static void kona_ccu_teardown(struct ccu_data *ccu) static void kona_ccu_teardown(struct ccu_data *ccu)
{ {
if (!ccu) kfree(ccu->clk_data.clks);
return; ccu->clk_data.clks = NULL;
if (!ccu->base) if (!ccu->base)
goto done; return;
of_clk_del_provider(ccu->node); /* safe if never added */ of_clk_del_provider(ccu->node); /* safe if never added */
ccu_clks_teardown(ccu); ccu_clks_teardown(ccu);
list_del(&ccu->links); list_del(&ccu->links);
of_node_put(ccu->node); of_node_put(ccu->node);
ccu->node = NULL;
iounmap(ccu->base); iounmap(ccu->base);
done: ccu->base = NULL;
kfree(ccu->name);
kfree(ccu);
} }
/* /*
* Set up a CCU. Call the provided ccu_clks_setup callback to * Set up a CCU. Call the provided ccu_clks_setup callback to
* initialize the array of clocks provided by the CCU. * initialize the array of clocks provided by the CCU.
*/ */
void __init kona_dt_ccu_setup(struct device_node *node, void __init kona_dt_ccu_setup(struct ccu_data *ccu,
struct device_node *node,
int (*ccu_clks_setup)(struct ccu_data *)) int (*ccu_clks_setup)(struct ccu_data *))
{ {
struct ccu_data *ccu;
struct resource res = { 0 }; struct resource res = { 0 };
resource_size_t range; resource_size_t range;
int ret; int ret;
ccu = kzalloc(sizeof(*ccu), GFP_KERNEL); if (ccu->clk_data.clk_num) {
if (ccu) size_t size;
ccu->name = kstrdup(node->name, GFP_KERNEL);
if (!ccu || !ccu->name) {
pr_err("%s: unable to allocate CCU struct for %s\n",
__func__, node->name);
kfree(ccu);
size = ccu->clk_data.clk_num * sizeof(*ccu->clk_data.clks);
ccu->clk_data.clks = kzalloc(size, GFP_KERNEL);
if (!ccu->clk_data.clks) {
pr_err("%s: unable to allocate %u clocks for %s\n",
__func__, ccu->clk_data.clk_num, node->name);
return; return;
} }
}
ret = of_address_to_resource(node, 0, &res); ret = of_address_to_resource(node, 0, &res);
if (ret) { if (ret) {
...@@ -742,18 +741,14 @@ void __init kona_dt_ccu_setup(struct device_node *node, ...@@ -742,18 +741,14 @@ void __init kona_dt_ccu_setup(struct device_node *node,
node->name); node->name);
goto out_err; goto out_err;
} }
spin_lock_init(&ccu->lock);
INIT_LIST_HEAD(&ccu->links);
ccu->node = of_node_get(node); ccu->node = of_node_get(node);
list_add_tail(&ccu->links, &ccu_list); list_add_tail(&ccu->links, &ccu_list);
/* Set up clocks array (in ccu->data) */ /* Set up clocks array (in ccu->clk_data) */
if (ccu_clks_setup(ccu)) if (ccu_clks_setup(ccu))
goto out_err; goto out_err;
ret = of_clk_add_provider(node, of_clk_src_onecell_get, &ccu->data); ret = of_clk_add_provider(node, of_clk_src_onecell_get, &ccu->clk_data);
if (ret) { if (ret) {
pr_err("%s: error adding ccu %s as provider (%d)\n", __func__, pr_err("%s: error adding ccu %s as provider (%d)\n", __func__,
node->name, ret); node->name, ret);
......
...@@ -1020,13 +1020,13 @@ bool __init kona_ccu_init(struct ccu_data *ccu) ...@@ -1020,13 +1020,13 @@ bool __init kona_ccu_init(struct ccu_data *ccu)
{ {
unsigned long flags; unsigned long flags;
unsigned int which; unsigned int which;
struct clk **clks = ccu->data.clks; struct clk **clks = ccu->clk_data.clks;
bool success = true; bool success = true;
flags = ccu_lock(ccu); flags = ccu_lock(ccu);
__ccu_write_enable(ccu); __ccu_write_enable(ccu);
for (which = 0; which < ccu->data.clk_num; which++) { for (which = 0; which < ccu->clk_data.clk_num; which++) {
struct kona_clk *bcm_clk; struct kona_clk *bcm_clk;
if (!clks[which]) if (!clks[which])
......
...@@ -85,11 +85,20 @@ struct ccu_data { ...@@ -85,11 +85,20 @@ struct ccu_data {
bool write_enabled; /* write access is currently enabled */ bool write_enabled; /* write access is currently enabled */
struct list_head links; /* for ccu_list */ struct list_head links; /* for ccu_list */
struct device_node *node; struct device_node *node;
struct clk_onecell_data data; struct clk_onecell_data clk_data;
const char *name; const char *name;
u32 range; /* byte range of address space */ u32 range; /* byte range of address space */
}; };
/* Initialization for common fields in a Kona ccu_data structure */
#define KONA_CCU_COMMON(_prefix, _name, _ucase_name) \
.name = #_name "_ccu", \
.lock = __SPIN_LOCK_UNLOCKED(_name ## _ccu_data.lock), \
.links = LIST_HEAD_INIT(_name ## _ccu_data.links), \
.clk_data = { \
.clk_num = _prefix ## _ ## _ucase_name ## _CCU_CLOCK_COUNT, \
}
/* /*
* Gating control and status is managed by a 32-bit gate register. * Gating control and status is managed by a 32-bit gate register.
* *
...@@ -390,8 +399,11 @@ extern struct clk_ops kona_peri_clk_ops; ...@@ -390,8 +399,11 @@ extern struct clk_ops kona_peri_clk_ops;
/* Help functions */ /* Help functions */
#define PERI_CLK_SETUP(clks, ccu, id, name) \ #define KONA_CLK_SETUP(_ccu, _type, _name) \
clks[id] = kona_clk_setup(ccu, #name, bcm_clk_peri, &name ## _data) kona_clk_setup((_ccu), #_name, bcm_clk_## _type, &_name ## _data)
#define PERI_CLK_SETUP(_ccu, _id, _name) \
(_ccu)->clk_data.clks[_id] = KONA_CLK_SETUP((_ccu), peri, _name)
/* Externally visible functions */ /* Externally visible functions */
...@@ -402,7 +414,8 @@ extern u64 scaled_div_build(struct bcm_clk_div *div, u32 div_value, ...@@ -402,7 +414,8 @@ extern u64 scaled_div_build(struct bcm_clk_div *div, u32 div_value,
extern struct clk *kona_clk_setup(struct ccu_data *ccu, const char *name, extern struct clk *kona_clk_setup(struct ccu_data *ccu, const char *name,
enum bcm_clk_type type, void *data); enum bcm_clk_type type, void *data);
extern void __init kona_dt_ccu_setup(struct device_node *node, extern void __init kona_dt_ccu_setup(struct ccu_data *ccu,
struct device_node *node,
int (*ccu_clks_setup)(struct ccu_data *)); int (*ccu_clks_setup)(struct ccu_data *));
extern bool __init kona_ccu_init(struct ccu_data *ccu); extern bool __init kona_ccu_init(struct ccu_data *ccu);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment