summaryrefslogtreecommitdiff
path: root/arch/arm/mach-omap2/omap_hwmod.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/arm/mach-omap2/omap_hwmod.c')
-rw-r--r--arch/arm/mach-omap2/omap_hwmod.c522
1 files changed, 221 insertions, 301 deletions
diff --git a/arch/arm/mach-omap2/omap_hwmod.c b/arch/arm/mach-omap2/omap_hwmod.c
index b5531dd3ae9c..111677878d9c 100644
--- a/arch/arm/mach-omap2/omap_hwmod.c
+++ b/arch/arm/mach-omap2/omap_hwmod.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* omap_hwmod implementation for OMAP2/3/4
*
@@ -10,10 +11,6 @@
* Tony Lindgren, Rajendra Nayak, Vikram Pandita, Sakari Poussa, Anand
* Sawant, Santosh Shilimkar, Richard Woodruff
*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
* Introduction
* ------------
* One way to view an OMAP SoC is as a collection of largely unrelated
@@ -155,6 +152,8 @@
#include "soc.h"
#include "common.h"
#include "clockdomain.h"
+#include "hdq1w.h"
+#include "mmc.h"
#include "powerdomain.h"
#include "cm2xxx.h"
#include "cm3xxx.h"
@@ -165,6 +164,7 @@
#include "prm33xx.h"
#include "prminst44xx.h"
#include "pm.h"
+#include "wd_timer.h"
/* Name of the OMAP hwmod for the MPU */
#define MPU_INITIATOR_NAME "mpu"
@@ -205,6 +205,20 @@ struct clkctrl_provider {
static LIST_HEAD(clkctrl_providers);
/**
+ * struct omap_hwmod_reset - IP specific reset functions
+ * @match: string to match against the module name
+ * @len: number of characters to match
+ * @reset: IP specific reset function
+ *
+ * Used only in cases where struct omap_hwmod is dynamically allocated.
+ */
+struct omap_hwmod_reset {
+ const char *match;
+ int len;
+ int (*reset)(struct omap_hwmod *oh);
+};
+
+/**
* struct omap_hwmod_soc_ops - fn ptrs for some SoC-specific operations
* @enable_module: function to enable a module (via MODULEMODE)
* @disable_module: function to disable a module (via MODULEMODE)
@@ -235,6 +249,7 @@ static struct omap_hwmod_soc_ops soc_ops;
/* omap_hwmod_list contains all registered struct omap_hwmods */
static LIST_HEAD(omap_hwmod_list);
+static DEFINE_MUTEX(list_lock);
/* mpu_oh: used to add/remove MPU initiator from sleepdep list */
static struct omap_hwmod *mpu_oh;
@@ -608,50 +623,20 @@ static int _enable_wakeup(struct omap_hwmod *oh, u32 *v)
return 0;
}
-/**
- * _disable_wakeup: clear OCP_SYSCONFIG.ENAWAKEUP bit in the hardware
- * @oh: struct omap_hwmod *
- *
- * Prevent the hardware module @oh to send wakeups. Returns -EINVAL
- * upon error or 0 upon success.
- */
-static int _disable_wakeup(struct omap_hwmod *oh, u32 *v)
-{
- if (!oh->class->sysc ||
- !((oh->class->sysc->sysc_flags & SYSC_HAS_ENAWAKEUP) ||
- (oh->class->sysc->idlemodes & SIDLE_SMART_WKUP) ||
- (oh->class->sysc->idlemodes & MSTANDBY_SMART_WKUP)))
- return -EINVAL;
-
- if (!oh->class->sysc->sysc_fields) {
- WARN(1, "omap_hwmod: %s: offset struct for sysconfig not provided in class\n", oh->name);
- return -EINVAL;
- }
-
- if (oh->class->sysc->sysc_flags & SYSC_HAS_ENAWAKEUP)
- *v &= ~(0x1 << oh->class->sysc->sysc_fields->enwkup_shift);
-
- if (oh->class->sysc->idlemodes & SIDLE_SMART_WKUP)
- _set_slave_idlemode(oh, HWMOD_IDLEMODE_SMART, v);
- if (oh->class->sysc->idlemodes & MSTANDBY_SMART_WKUP)
- _set_master_standbymode(oh, HWMOD_IDLEMODE_SMART, v);
-
- /* XXX test pwrdm_get_wken for this hwmod's subsystem */
-
- return 0;
-}
-
static struct clockdomain *_get_clkdm(struct omap_hwmod *oh)
{
struct clk_hw_omap *clk;
+ if (!oh)
+ return NULL;
+
if (oh->clkdm) {
return oh->clkdm;
} else if (oh->_clk) {
- if (__clk_get_flags(oh->_clk) & CLK_IS_BASIC)
+ if (!omap2_clk_is_hw_omap(__clk_get_hw(oh->_clk)))
return NULL;
clk = to_clk_hw_omap(__clk_get_hw(oh->_clk));
- return clk->clkdm;
+ return clk->clkdm;
}
return NULL;
}
@@ -721,9 +706,7 @@ static const struct of_device_id ti_clkctrl_match_table[] __initconst = {
static int __init _setup_clkctrl_provider(struct device_node *np)
{
- const __be32 *addrp;
struct clkctrl_provider *provider;
- u64 size;
int i;
provider = memblock_alloc(sizeof(*provider), SMP_CACHE_BYTES);
@@ -732,8 +715,7 @@ static int __init _setup_clkctrl_provider(struct device_node *np)
provider->node = np;
- provider->num_addrs =
- of_property_count_elems_of_size(np, "reg", sizeof(u32)) / 2;
+ provider->num_addrs = of_address_count(np);
provider->addr =
memblock_alloc(sizeof(void *) * provider->num_addrs,
@@ -748,11 +730,11 @@ static int __init _setup_clkctrl_provider(struct device_node *np)
return -ENOMEM;
for (i = 0; i < provider->num_addrs; i++) {
- addrp = of_get_address(np, i, &size, NULL);
- provider->addr[i] = (u32)of_translate_address(np, addrp);
- provider->size[i] = size;
- pr_debug("%s: %pOF: %x...%x\n", __func__, np, provider->addr[i],
- provider->addr[i] + provider->size[i]);
+ struct resource res;
+ of_address_to_resource(np, i, &res);
+ provider->addr[i] = res.start;
+ provider->size[i] = resource_size(&res);
+ pr_debug("%s: %pOF: %pR\n", __func__, np, &res);
}
list_add(&provider->link, &clkctrl_providers);
@@ -767,8 +749,10 @@ static int __init _init_clkctrl_providers(void)
for_each_matching_node(np, ti_clkctrl_match_table) {
ret = _setup_clkctrl_provider(np);
- if (ret)
+ if (ret) {
+ of_node_put(np);
break;
+ }
}
return ret;
@@ -827,7 +811,7 @@ static struct clk *_lookup_clkctrl_clk(struct omap_hwmod *oh)
}
/**
- * _init_main_clk - get a struct clk * for the the hwmod's main functional clk
+ * _init_main_clk - get a struct clk * for the hwmod's main functional clk
* @oh: struct omap_hwmod *
*
* Called from _init_clocks(). Populates the @oh _clk (main
@@ -877,7 +861,7 @@ static int _init_main_clk(struct omap_hwmod *oh)
}
/**
- * _init_interface_clks - get a struct clk * for the the hwmod's interface clks
+ * _init_interface_clks - get a struct clk * for the hwmod's interface clks
* @oh: struct omap_hwmod *
*
* Called from _init_clocks(). Populates the @oh OCP slave interface
@@ -916,7 +900,7 @@ static int _init_interface_clks(struct omap_hwmod *oh)
}
/**
- * _init_opt_clk - get a struct clk * for the the hwmod's optional clocks
+ * _init_opt_clks - get a struct clk * for the hwmod's optional clocks
* @oh: struct omap_hwmod *
*
* Called from _init_clocks(). Populates the @oh omap_hwmod_opt_clk
@@ -1002,8 +986,10 @@ static int _enable_clocks(struct omap_hwmod *oh)
clk_enable(oh->_clk);
list_for_each_entry(os, &oh->slave_ports, node) {
- if (os->_clk && (os->flags & OCPIF_SWSUP_IDLE))
+ if (os->_clk && (os->flags & OCPIF_SWSUP_IDLE)) {
+ omap2_clk_deny_idle(os->_clk);
clk_enable(os->_clk);
+ }
}
/* The opt clocks are controlled by the device driver. */
@@ -1055,8 +1041,10 @@ static int _disable_clocks(struct omap_hwmod *oh)
clk_disable(oh->_clk);
list_for_each_entry(os, &oh->slave_ports, node) {
- if (os->_clk && (os->flags & OCPIF_SWSUP_IDLE))
+ if (os->_clk && (os->flags & OCPIF_SWSUP_IDLE)) {
clk_disable(os->_clk);
+ omap2_clk_allow_idle(os->_clk);
+ }
}
if (oh->flags & HWMOD_OPT_CLKS_NEEDED)
@@ -1867,23 +1855,6 @@ static int _omap4_get_context_lost(struct omap_hwmod *oh)
}
/**
- * _enable_preprogram - Pre-program an IP block during the _enable() process
- * @oh: struct omap_hwmod *
- *
- * Some IP blocks (such as AESS) require some additional programming
- * after enable before they can enter idle. If a function pointer to
- * do so is present in the hwmod data, then call it and pass along the
- * return value; otherwise, return 0.
- */
-static int _enable_preprogram(struct omap_hwmod *oh)
-{
- if (!oh->class->enable_preprogram)
- return 0;
-
- return oh->class->enable_preprogram(oh);
-}
-
-/**
* _enable - enable an omap_hwmod
* @oh: struct omap_hwmod *
*
@@ -1966,7 +1937,6 @@ static int _enable(struct omap_hwmod *oh)
_update_sysc_cache(oh);
_enable_sysc(oh);
}
- r = _enable_preprogram(oh);
} else {
if (soc_ops.disable_module)
soc_ops.disable_module(oh);
@@ -2166,6 +2136,7 @@ static int of_dev_hwmod_lookup(struct device_node *np,
if (res == 0) {
*found = fc;
*index = i;
+ of_node_put(np0);
return 0;
}
}
@@ -2223,23 +2194,8 @@ int omap_hwmod_parse_module_range(struct omap_hwmod *oh,
struct resource *res)
{
struct property *prop;
- const __be32 *ranges;
const char *name;
- u32 nr_addr, nr_size;
- u64 base, size;
- int len, error;
-
- if (!res)
- return -EINVAL;
-
- ranges = of_get_property(np, "ranges", &len);
- if (!ranges)
- return -ENOENT;
-
- len /= sizeof(*ranges);
-
- if (len < 3)
- return -EINVAL;
+ int err;
of_property_for_each_string(np, "compatible", prop, name)
if (!strncmp("ti,sysc-", name, 8))
@@ -2248,26 +2204,12 @@ int omap_hwmod_parse_module_range(struct omap_hwmod *oh,
if (!name)
return -ENOENT;
- error = of_property_read_u32(np, "#address-cells", &nr_addr);
- if (error)
- return -ENOENT;
+ err = of_range_to_resource(np, 0, res);
+ if (err)
+ return err;
- error = of_property_read_u32(np, "#size-cells", &nr_size);
- if (error)
- return -ENOENT;
-
- if (nr_addr != 1 || nr_size != 1) {
- pr_err("%s: invalid range for %s->%pOFn\n", __func__,
- oh->name, np);
- return -EINVAL;
- }
-
- ranges++;
- base = of_translate_address(np, ranges++);
- size = be32_to_cpup(ranges);
-
- pr_debug("omap_hwmod: %s %pOFn at 0x%llx size 0x%llx\n",
- oh->name, np, base, size);
+ pr_debug("omap_hwmod: %s %pOFn at %pR\n",
+ oh->name, np, res);
if (oh && oh->mpu_rt_idx) {
omap_hwmod_fix_mpu_rt_idx(oh, np, res);
@@ -2275,10 +2217,6 @@ int omap_hwmod_parse_module_range(struct omap_hwmod *oh,
return 0;
}
- res->start = base;
- res->end = base + size - 1;
- res->flags = IORESOURCE_MEM;
-
return 0;
}
@@ -2348,18 +2286,18 @@ static int __init _init_mpu_rt_base(struct omap_hwmod *oh, void *data,
static void __init parse_module_flags(struct omap_hwmod *oh,
struct device_node *np)
{
- if (of_find_property(np, "ti,no-reset-on-init", NULL))
+ if (of_property_read_bool(np, "ti,no-reset-on-init"))
oh->flags |= HWMOD_INIT_NO_RESET;
- if (of_find_property(np, "ti,no-idle-on-init", NULL))
+ if (of_property_read_bool(np, "ti,no-idle-on-init"))
oh->flags |= HWMOD_INIT_NO_IDLE;
- if (of_find_property(np, "ti,no-idle", NULL))
+ if (of_property_read_bool(np, "ti,no-idle"))
oh->flags |= HWMOD_NO_IDLE;
}
/**
* _init - initialize internal data for the hwmod @oh
* @oh: struct omap_hwmod *
- * @n: (unused)
+ * @data: (unused)
*
* Look up the clocks and the address space used by the MPU to access
* registers belonging to the hwmod @oh. @oh must already be
@@ -2436,9 +2374,13 @@ static void _setup_iclk_autoidle(struct omap_hwmod *oh)
continue;
if (os->flags & OCPIF_SWSUP_IDLE) {
- /* XXX omap_iclk_deny_idle(c); */
+ /*
+ * we might have multiple users of one iclk with
+ * different requirements, disable autoidle when
+ * the module is enabled, e.g. dss iclk
+ */
} else {
- /* XXX omap_iclk_allow_idle(c); */
+ /* we are enabling autoidle afterwards anyways */
clk_enable(os->_clk);
}
}
@@ -2457,7 +2399,7 @@ static void _setup_iclk_autoidle(struct omap_hwmod *oh)
*/
static int _setup_reset(struct omap_hwmod *oh)
{
- int r;
+ int r = 0;
if (oh->_state != _HWMOD_STATE_INITIALIZED)
return -EINVAL;
@@ -2551,7 +2493,7 @@ static void _setup_postsetup(struct omap_hwmod *oh)
/**
* _setup - prepare IP block hardware for use
* @oh: struct omap_hwmod *
- * @n: (unused, pass NULL)
+ * @data: (unused, pass NULL)
*
* Configure the IP block represented by @oh. This may include
* enabling the IP block, resetting it, and placing it into a
@@ -2616,7 +2558,7 @@ static int _setup(struct omap_hwmod *oh, void *data)
* that the copy process would be relatively complex due to the large number
* 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 ||
(oh->_state != _HWMOD_STATE_UNKNOWN))
@@ -2655,7 +2597,7 @@ static int __init _register(struct omap_hwmod *oh)
* locking in this code. Changes to this assumption will require
* 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,
oi->slave->name);
@@ -3076,6 +3018,8 @@ int __init omap_hwmod_register_links(struct omap_hwmod_ocp_if **ois)
return 0;
}
+static int __init omap_hwmod_setup_one(const char *oh_name);
+
/**
* _ensure_mpu_hwmod_is_setup - ensure the MPU SS hwmod is init'ed and set up
* @oh: pointer to the hwmod currently being set up (usually not the MPU)
@@ -3106,7 +3050,7 @@ static void __init _ensure_mpu_hwmod_is_setup(struct omap_hwmod *oh)
* registered omap_hwmod. Also calls _setup() on each hwmod. Returns
* -EINVAL upon error or 0 upon success.
*/
-int __init omap_hwmod_setup_one(const char *oh_name)
+static int __init omap_hwmod_setup_one(const char *oh_name)
{
struct omap_hwmod *oh;
@@ -3176,15 +3120,14 @@ static int omap_hwmod_check_sysc(struct device *dev,
/**
* omap_hwmod_init_regbits - init sysconfig specific register bits
* @dev: struct device
+ * @oh: module
* @data: module data
* @sysc_fields: new sysc configuration
*/
-static int omap_hwmod_init_regbits(struct device *dev,
+static int omap_hwmod_init_regbits(struct device *dev, struct omap_hwmod *oh,
const struct ti_sysc_module_data *data,
struct sysc_regbits **sysc_fields)
{
- *sysc_fields = NULL;
-
switch (data->cap->type) {
case TI_SYSC_OMAP2:
case TI_SYSC_OMAP2_TIMER:
@@ -3219,6 +3162,12 @@ static int omap_hwmod_init_regbits(struct device *dev,
*sysc_fields = &omap_hwmod_sysc_type_usb_host_fs;
break;
default:
+ *sysc_fields = NULL;
+ if (!oh->class->sysc->sysc_fields)
+ return 0;
+
+ dev_err(dev, "sysc_fields not found\n");
+
return -EINVAL;
}
@@ -3233,9 +3182,10 @@ static int omap_hwmod_init_regbits(struct device *dev,
* @sysc_offs: sysc register offset
* @syss_offs: syss register offset
*/
-int omap_hwmod_init_reg_offs(struct device *dev,
- const struct ti_sysc_module_data *data,
- s32 *rev_offs, s32 *sysc_offs, s32 *syss_offs)
+static int omap_hwmod_init_reg_offs(struct device *dev,
+ const struct ti_sysc_module_data *data,
+ s32 *rev_offs, s32 *sysc_offs,
+ s32 *syss_offs)
{
*rev_offs = -ENODEV;
*sysc_offs = 0;
@@ -3259,9 +3209,9 @@ int omap_hwmod_init_reg_offs(struct device *dev,
* @data: module data
* @sysc_flags: module configuration
*/
-int omap_hwmod_init_sysc_flags(struct device *dev,
- const struct ti_sysc_module_data *data,
- u32 *sysc_flags)
+static int omap_hwmod_init_sysc_flags(struct device *dev,
+ const struct ti_sysc_module_data *data,
+ u32 *sysc_flags)
{
*sysc_flags = 0;
@@ -3333,9 +3283,9 @@ int omap_hwmod_init_sysc_flags(struct device *dev,
* @data: module data
* @idlemodes: module supported idle modes
*/
-int omap_hwmod_init_idlemodes(struct device *dev,
- const struct ti_sysc_module_data *data,
- u32 *idlemodes)
+static int omap_hwmod_init_idlemodes(struct device *dev,
+ const struct ti_sysc_module_data *data,
+ u32 *idlemodes)
{
*idlemodes = 0;
@@ -3383,9 +3333,9 @@ static int omap_hwmod_check_module(struct device *dev,
if (!oh->class->sysc)
return -ENODEV;
- if (sysc_fields != oh->class->sysc->sysc_fields)
- dev_warn(dev, "sysc_fields %p != %p\n", sysc_fields,
- oh->class->sysc->sysc_fields);
+ if (oh->class->sysc->sysc_fields &&
+ sysc_fields != oh->class->sysc->sysc_fields)
+ dev_warn(dev, "sysc_fields mismatch\n");
if (rev_offs != oh->class->sysc->rev_offs)
dev_warn(dev, "rev_offs %08x != %08x\n", rev_offs,
@@ -3417,7 +3367,9 @@ static int omap_hwmod_check_module(struct device *dev,
* omap_hwmod_allocate_module - allocate new module
* @dev: struct device
* @oh: module
+ * @data: module data
* @sysc_fields: sysc register bits
+ * @clkdm: clockdomain
* @rev_offs: revision register offset
* @sysc_offs: sysconfig register offset
* @syss_offs: sysstatus register offset
@@ -3426,14 +3378,17 @@ static int omap_hwmod_check_module(struct device *dev,
*
* Note that the allocations here cannot use devm as ti-sysc can rebind.
*/
-int omap_hwmod_allocate_module(struct device *dev, struct omap_hwmod *oh,
- const struct ti_sysc_module_data *data,
- struct sysc_regbits *sysc_fields,
- s32 rev_offs, s32 sysc_offs, s32 syss_offs,
- u32 sysc_flags, u32 idlemodes)
+static int omap_hwmod_allocate_module(struct device *dev, struct omap_hwmod *oh,
+ const struct ti_sysc_module_data *data,
+ struct sysc_regbits *sysc_fields,
+ struct clockdomain *clkdm,
+ s32 rev_offs, s32 sysc_offs,
+ s32 syss_offs, u32 sysc_flags,
+ u32 idlemodes)
{
struct omap_hwmod_class_sysconfig *sysc;
- struct omap_hwmod_class *class;
+ struct omap_hwmod_class *class = NULL;
+ struct omap_hwmod_ocp_if *oi = NULL;
void __iomem *regs = NULL;
unsigned long flags;
@@ -3453,28 +3408,100 @@ int omap_hwmod_allocate_module(struct device *dev, struct omap_hwmod *oh,
regs = ioremap(data->module_pa,
data->module_size);
if (!regs)
- return -ENOMEM;
+ goto out_free_sysc;
}
/*
- * We need new oh->class as the other devices in the same class
+ * We may need a new oh->class as the other devices in the same class
* may not yet have ioremapped their registers.
*/
- class = kmemdup(oh->class, sizeof(*oh->class), GFP_KERNEL);
- if (!class)
- return -ENOMEM;
+ if (oh->class->name && strcmp(oh->class->name, data->name)) {
+ class = kmemdup(oh->class, sizeof(*oh->class), GFP_KERNEL);
+ if (!class)
+ goto out_unmap;
+ }
- class->sysc = sysc;
+ if (list_empty(&oh->slave_ports)) {
+ oi = kzalloc(sizeof(*oi), GFP_KERNEL);
+ if (!oi)
+ goto out_free_class;
+
+ /*
+ * 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;
+ }
spin_lock_irqsave(&oh->_lock, flags);
if (regs)
oh->_mpu_rt_va = regs;
- oh->class = class;
+ if (class)
+ oh->class = class;
+ oh->class->sysc = sysc;
+ if (oi)
+ _add_link(oi);
+ if (clkdm)
+ oh->clkdm = clkdm;
oh->_state = _HWMOD_STATE_INITIALIZED;
+ oh->_postsetup_state = _HWMOD_STATE_DEFAULT;
_setup(oh, NULL);
spin_unlock_irqrestore(&oh->_lock, flags);
return 0;
+
+out_free_class:
+ kfree(class);
+out_unmap:
+ iounmap(regs);
+out_free_sysc:
+ kfree(sysc);
+ return -ENOMEM;
+}
+
+static const struct omap_hwmod_reset omap24xx_reset_quirks[] = {
+ { .match = "msdi", .len = 4, .reset = omap_msdi_reset, },
+};
+
+static const struct omap_hwmod_reset omap_reset_quirks[] = {
+ { .match = "dss_core", .len = 8, .reset = omap_dss_reset, },
+ { .match = "hdq1w", .len = 5, .reset = omap_hdq1w_reset, },
+ { .match = "i2c", .len = 3, .reset = omap_i2c_reset, },
+ { .match = "wd_timer", .len = 8, .reset = omap2_wd_timer_reset, },
+};
+
+static void
+omap_hwmod_init_reset_quirk(struct device *dev, struct omap_hwmod *oh,
+ const struct ti_sysc_module_data *data,
+ const struct omap_hwmod_reset *quirks,
+ int quirks_sz)
+{
+ const struct omap_hwmod_reset *quirk;
+ int i;
+
+ for (i = 0; i < quirks_sz; i++) {
+ quirk = &quirks[i];
+ if (!strncmp(data->name, quirk->match, quirk->len)) {
+ oh->class->reset = quirk->reset;
+
+ return;
+ }
+ }
+}
+
+static void
+omap_hwmod_init_reset_quirks(struct device *dev, struct omap_hwmod *oh,
+ const struct ti_sysc_module_data *data)
+{
+ if (soc_is_omap24xx())
+ omap_hwmod_init_reset_quirk(dev, oh, data,
+ omap24xx_reset_quirks,
+ ARRAY_SIZE(omap24xx_reset_quirks));
+
+ omap_hwmod_init_reset_quirk(dev, oh, data, omap_reset_quirks,
+ ARRAY_SIZE(omap_reset_quirks));
}
/**
@@ -3493,16 +3520,39 @@ int omap_hwmod_init_module(struct device *dev,
u32 sysc_flags, idlemodes;
int error;
- if (!dev || !data)
+ if (!dev || !data || !data->name || !cookie)
return -EINVAL;
oh = _lookup(data->name);
- if (!oh)
- return -ENODEV;
+ if (!oh) {
+ oh = kzalloc(sizeof(*oh), GFP_KERNEL);
+ if (!oh)
+ 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;
+ }
+
+ omap_hwmod_init_reset_quirks(dev, oh, data);
+
+ oh->class->name = data->name;
+ mutex_lock(&list_lock);
+ error = _register(oh);
+ mutex_unlock(&list_lock);
+ }
cookie->data = oh;
- error = omap_hwmod_init_regbits(dev, data, &sysc_fields);
+ error = omap_hwmod_init_regbits(dev, oh, data, &sysc_fields);
if (error)
return error;
@@ -3519,10 +3569,22 @@ int omap_hwmod_init_module(struct device *dev,
if (error)
return error;
+ if (data->cfg->quirks & SYSC_QUIRK_NO_IDLE)
+ oh->flags |= HWMOD_NO_IDLE;
if (data->cfg->quirks & SYSC_QUIRK_NO_IDLE_ON_INIT)
oh->flags |= HWMOD_INIT_NO_IDLE;
if (data->cfg->quirks & SYSC_QUIRK_NO_RESET_ON_INIT)
oh->flags |= HWMOD_INIT_NO_RESET;
+ if (data->cfg->quirks & SYSC_QUIRK_USE_CLOCKACT)
+ oh->flags |= HWMOD_SET_DEFAULT_CLOCKACT;
+ if (data->cfg->quirks & SYSC_QUIRK_SWSUP_SIDLE)
+ oh->flags |= HWMOD_SWSUP_SIDLE;
+ if (data->cfg->quirks & SYSC_QUIRK_SWSUP_SIDLE_ACT)
+ oh->flags |= HWMOD_SWSUP_SIDLE_ACT;
+ if (data->cfg->quirks & SYSC_QUIRK_SWSUP_MSTANDBY)
+ oh->flags |= HWMOD_SWSUP_MSTANDBY;
+ if (data->cfg->quirks & SYSC_QUIRK_CLKDM_NOAUTO)
+ oh->flags |= HWMOD_CLKDM_NOAUTO;
error = omap_hwmod_check_module(dev, oh, data, sysc_fields,
rev_offs, sysc_offs, syss_offs,
@@ -3531,7 +3593,8 @@ int omap_hwmod_init_module(struct device *dev,
return error;
return omap_hwmod_allocate_module(dev, oh, data, sysc_fields,
- rev_offs, sysc_offs, syss_offs,
+ cookie->clkdm, rev_offs,
+ sysc_offs, syss_offs,
sysc_flags, idlemodes);
}
@@ -3581,6 +3644,9 @@ static void __init omap_hwmod_setup_earlycon_flags(void)
*/
static int __init omap_hwmod_setup_all(void)
{
+ if (!inited)
+ return 0;
+
_ensure_mpu_hwmod_is_setup(NULL);
omap_hwmod_for_each(_init, NULL);
@@ -3665,47 +3731,6 @@ int omap_hwmod_shutdown(struct omap_hwmod *oh)
*/
/**
- * omap_hwmod_get_pwrdm - return pointer to this module's main powerdomain
- * @oh: struct omap_hwmod *
- *
- * Return the powerdomain pointer associated with the OMAP module
- * @oh's main clock. If @oh does not have a main clk, return the
- * powerdomain associated with the interface clock associated with the
- * module's MPU port. (XXX Perhaps this should use the SDMA port
- * instead?) Returns NULL on error, or a struct powerdomain * on
- * success.
- */
-struct powerdomain *omap_hwmod_get_pwrdm(struct omap_hwmod *oh)
-{
- struct clk *c;
- struct omap_hwmod_ocp_if *oi;
- struct clockdomain *clkdm;
- struct clk_hw_omap *clk;
-
- if (!oh)
- return NULL;
-
- if (oh->clkdm)
- return oh->clkdm->pwrdm.ptr;
-
- if (oh->_clk) {
- c = oh->_clk;
- } else {
- oi = _find_mpu_rt_port(oh);
- if (!oi)
- return NULL;
- c = oi->_clk;
- }
-
- clk = to_clk_hw_omap(__clk_get_hw(c));
- clkdm = clk->clkdm;
- if (!clkdm)
- return NULL;
-
- return clkdm->pwrdm.ptr;
-}
-
-/**
* omap_hwmod_get_mpu_rt_va - return the module's base address (for the MPU)
* @oh: struct omap_hwmod *
*
@@ -3734,70 +3759,6 @@ void __iomem *omap_hwmod_get_mpu_rt_va(struct omap_hwmod *oh)
*/
/**
- * omap_hwmod_enable_wakeup - allow device to wake up the system
- * @oh: struct omap_hwmod *
- *
- * Sets the module OCP socket ENAWAKEUP bit to allow the module to
- * send wakeups to the PRCM, and enable I/O ring wakeup events for
- * this IP block if it has dynamic mux entries. Eventually this
- * should set PRCM wakeup registers to cause the PRCM to receive
- * wakeup events from the module. Does not set any wakeup routing
- * registers beyond this point - if the module is to wake up any other
- * module or subsystem, that must be set separately. Called by
- * omap_device code. Returns -EINVAL on error or 0 upon success.
- */
-int omap_hwmod_enable_wakeup(struct omap_hwmod *oh)
-{
- unsigned long flags;
- u32 v;
-
- spin_lock_irqsave(&oh->_lock, flags);
-
- if (oh->class->sysc &&
- (oh->class->sysc->sysc_flags & SYSC_HAS_ENAWAKEUP)) {
- v = oh->_sysc_cache;
- _enable_wakeup(oh, &v);
- _write_sysconfig(v, oh);
- }
-
- spin_unlock_irqrestore(&oh->_lock, flags);
-
- return 0;
-}
-
-/**
- * omap_hwmod_disable_wakeup - prevent device from waking the system
- * @oh: struct omap_hwmod *
- *
- * Clears the module OCP socket ENAWAKEUP bit to prevent the module
- * from sending wakeups to the PRCM, and disable I/O ring wakeup
- * events for this IP block if it has dynamic mux entries. Eventually
- * this should clear PRCM wakeup registers to cause the PRCM to ignore
- * wakeup events from the module. Does not set any wakeup routing
- * registers beyond this point - if the module is to wake up any other
- * module or subsystem, that must be set separately. Called by
- * omap_device code. Returns -EINVAL on error or 0 upon success.
- */
-int omap_hwmod_disable_wakeup(struct omap_hwmod *oh)
-{
- unsigned long flags;
- u32 v;
-
- spin_lock_irqsave(&oh->_lock, flags);
-
- if (oh->class->sysc &&
- (oh->class->sysc->sysc_flags & SYSC_HAS_ENAWAKEUP)) {
- v = oh->_sysc_cache;
- _disable_wakeup(oh, &v);
- _write_sysconfig(v, oh);
- }
-
- spin_unlock_irqrestore(&oh->_lock, flags);
-
- return 0;
-}
-
-/**
* omap_hwmod_assert_hardreset - assert the HW reset line of submodules
* contained in the hwmod module.
* @oh: struct omap_hwmod *
@@ -3935,32 +3896,6 @@ ohsps_unlock:
}
/**
- * omap_hwmod_get_context_loss_count - get lost context count
- * @oh: struct omap_hwmod *
- *
- * Returns the context loss count of associated @oh
- * upon success, or zero if no context loss data is available.
- *
- * On OMAP4, this queries the per-hwmod context loss register,
- * assuming one exists. If not, or on OMAP2/3, this queries the
- * enclosing powerdomain context loss count.
- */
-int omap_hwmod_get_context_loss_count(struct omap_hwmod *oh)
-{
- struct powerdomain *pwrdm;
- int ret = 0;
-
- if (soc_ops.get_context_lost)
- return soc_ops.get_context_lost(oh);
-
- pwrdm = omap_hwmod_get_pwrdm(oh);
- if (pwrdm)
- ret = pwrdm_get_context_loss_count(pwrdm);
-
- return ret;
-}
-
-/**
* omap_hwmod_init - initialize the hwmod code
*
* Sets up some function pointers needed by the hwmod code to operate on the
@@ -4011,18 +3946,3 @@ void __init omap_hwmod_init(void)
inited = true;
}
-
-/**
- * omap_hwmod_get_main_clk - get pointer to main clock name
- * @oh: struct omap_hwmod *
- *
- * Returns the main clock name assocated with @oh upon success,
- * or NULL if @oh is NULL.
- */
-const char *omap_hwmod_get_main_clk(struct omap_hwmod *oh)
-{
- if (!oh)
- return NULL;
-
- return oh->main_clk;
-}