diff options
Diffstat (limited to 'arch/arm/mach-omap2/omap_hwmod.c')
| -rw-r--r-- | arch/arm/mach-omap2/omap_hwmod.c | 522 |
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; -} |
