Commit b57250fa authored by Tony Lindgren's avatar Tony Lindgren

ARM: OMAP2+: Allocate struct omap_hwmod based on dts data

With ti-sysc interconnect target module, we can allocate struct omap_hwmod
data based on the devicetree data. This allows dropping the static SoC
specific data eventually so we will only boot with data we actually need.

To allocate struct omap_hwmod dynamically, we need to add a mutex for
modifying the list, and remove __init for few functions.

Note that we are not initialized oh->_clk or the optional clocks and their
related quirks. That can be directly handled by the interconnect target
module driver.

Cc: Paul Walmsley <paul@pwsan.com>
Cc: Tero Kristo <t-kristo@ti.com>
Signed-off-by: default avatarTony Lindgren <tony@atomide.com>
parent 6d63b12d
...@@ -235,6 +235,7 @@ static struct omap_hwmod_soc_ops soc_ops; ...@@ -235,6 +235,7 @@ static struct omap_hwmod_soc_ops soc_ops;
/* omap_hwmod_list contains all registered struct omap_hwmods */ /* omap_hwmod_list contains all registered struct omap_hwmods */
static LIST_HEAD(omap_hwmod_list); static LIST_HEAD(omap_hwmod_list);
static DEFINE_MUTEX(list_lock);
/* mpu_oh: used to add/remove MPU initiator from sleepdep list */ /* mpu_oh: used to add/remove MPU initiator from sleepdep list */
static struct omap_hwmod *mpu_oh; static struct omap_hwmod *mpu_oh;
...@@ -2624,7 +2625,7 @@ static int _setup(struct omap_hwmod *oh, void *data) ...@@ -2624,7 +2625,7 @@ static int _setup(struct omap_hwmod *oh, void *data)
* that the copy process would be relatively complex due to the large number * that the copy process would be relatively complex due to the large number
* of substructures. * of substructures.
*/ */
static int __init _register(struct omap_hwmod *oh) static int _register(struct omap_hwmod *oh)
{ {
if (!oh || !oh->name || !oh->class || !oh->class->name || if (!oh || !oh->name || !oh->class || !oh->class->name ||
(oh->_state != _HWMOD_STATE_UNKNOWN)) (oh->_state != _HWMOD_STATE_UNKNOWN))
...@@ -2663,7 +2664,7 @@ static int __init _register(struct omap_hwmod *oh) ...@@ -2663,7 +2664,7 @@ static int __init _register(struct omap_hwmod *oh)
* locking in this code. Changes to this assumption will require * locking in this code. Changes to this assumption will require
* additional locking. Returns 0. * additional locking. Returns 0.
*/ */
static int __init _add_link(struct omap_hwmod_ocp_if *oi) static int _add_link(struct omap_hwmod_ocp_if *oi)
{ {
pr_debug("omap_hwmod: %s -> %s: adding link\n", oi->master->name, pr_debug("omap_hwmod: %s -> %s: adding link\n", oi->master->name,
oi->slave->name); oi->slave->name);
...@@ -3444,6 +3445,9 @@ static int omap_hwmod_allocate_module(struct device *dev, struct omap_hwmod *oh, ...@@ -3444,6 +3445,9 @@ static int omap_hwmod_allocate_module(struct device *dev, struct omap_hwmod *oh,
{ {
struct omap_hwmod_class_sysconfig *sysc; struct omap_hwmod_class_sysconfig *sysc;
struct omap_hwmod_class *class = NULL; struct omap_hwmod_class *class = NULL;
struct omap_hwmod_ocp_if *oi = NULL;
struct clockdomain *clkdm = NULL;
struct clk *clk = NULL;
void __iomem *regs = NULL; void __iomem *regs = NULL;
unsigned long flags; unsigned long flags;
...@@ -3476,13 +3480,62 @@ static int omap_hwmod_allocate_module(struct device *dev, struct omap_hwmod *oh, ...@@ -3476,13 +3480,62 @@ static int omap_hwmod_allocate_module(struct device *dev, struct omap_hwmod *oh,
return -ENOMEM; return -ENOMEM;
} }
if (list_empty(&oh->slave_ports)) {
oi = kcalloc(1, sizeof(*oi), GFP_KERNEL);
if (!oi)
return -ENOMEM;
/*
* Note that we assume interconnect interface clocks will be
* managed by the interconnect driver for OCPIF_SWSUP_IDLE case
* on omap24xx and omap3.
*/
oi->slave = oh;
oi->user = OCP_USER_MPU | OCP_USER_SDMA;
}
if (!oh->_clk) {
struct clk_hw_omap *hwclk;
clk = of_clk_get_by_name(dev->of_node, "fck");
if (!IS_ERR(clk))
clk_prepare(clk);
else
clk = NULL;
/*
* Populate clockdomain based on dts clock. It is needed for
* clkdm_deny_idle() and clkdm_allow_idle() until we have have
* interconnect driver and reset driver capable of blocking
* clockdomain idle during reset, enable and idle.
*/
if (clk) {
hwclk = to_clk_hw_omap(__clk_get_hw(clk));
if (hwclk && hwclk->clkdm_name)
clkdm = clkdm_lookup(hwclk->clkdm_name);
}
/*
* Note that we assume interconnect driver manages the clocks
* and do not need to populate oh->_clk for dynamically
* allocated modules.
*/
clk_unprepare(clk);
clk_put(clk);
}
spin_lock_irqsave(&oh->_lock, flags); spin_lock_irqsave(&oh->_lock, flags);
if (regs) if (regs)
oh->_mpu_rt_va = regs; oh->_mpu_rt_va = regs;
if (class) if (class)
oh->class = class; oh->class = class;
oh->class->sysc = sysc; oh->class->sysc = sysc;
if (oi)
_add_link(oi);
if (clkdm)
oh->clkdm = clkdm;
oh->_state = _HWMOD_STATE_INITIALIZED; oh->_state = _HWMOD_STATE_INITIALIZED;
oh->_postsetup_state = _HWMOD_STATE_DEFAULT;
_setup(oh, NULL); _setup(oh, NULL);
spin_unlock_irqrestore(&oh->_lock, flags); spin_unlock_irqrestore(&oh->_lock, flags);
...@@ -3509,8 +3562,29 @@ int omap_hwmod_init_module(struct device *dev, ...@@ -3509,8 +3562,29 @@ int omap_hwmod_init_module(struct device *dev,
return -EINVAL; return -EINVAL;
oh = _lookup(data->name); oh = _lookup(data->name);
if (!oh) {
oh = kzalloc(sizeof(*oh), GFP_KERNEL);
if (!oh) if (!oh)
return -ENODEV; return -ENOMEM;
oh->name = data->name;
oh->_state = _HWMOD_STATE_UNKNOWN;
lockdep_register_key(&oh->hwmod_key);
/* Unused, can be handled by PRM driver handling resets */
oh->prcm.omap4.flags = HWMOD_OMAP4_NO_CONTEXT_LOSS_BIT;
oh->class = kzalloc(sizeof(*oh->class), GFP_KERNEL);
if (!oh->class) {
kfree(oh);
return -ENOMEM;
}
oh->class->name = data->name;
mutex_lock(&list_lock);
error = _register(oh);
mutex_unlock(&list_lock);
}
cookie->data = oh; cookie->data = oh;
......
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