From 9c8b0ec7a46c5840fddaa570933335f4ccbbd078 Mon Sep 17 00:00:00 2001 From: Paul Walmsley Date: Wed, 18 Apr 2012 19:10:02 -0600 Subject: ARM: OMAP2+: hwmod: control all hardreset lines attached to a hwmod MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Parts of the hwmod code test to see if a module has one and only one hardreset line before taking an action. It seems more appropriate to control all hardreset lines associated with a hwmod, not just one. It so happens that with the current hwmod data, this patch will not change any behavior, since hwmods with hardreset lines have only one hardreset line associated with them, and 'pseudo-hwmods' are used to handle the other hardreset lines. But future hwmod data patches to remove the pseudo-hwmods will change this. Signed-off-by: Paul Walmsley Cc: Benoît Cousson --- arch/arm/mach-omap2/omap_hwmod.c | 29 +++++++++++++++-------------- 1 file changed, 15 insertions(+), 14 deletions(-) (limited to 'arch/arm/mach-omap2/omap_hwmod.c') diff --git a/arch/arm/mach-omap2/omap_hwmod.c b/arch/arm/mach-omap2/omap_hwmod.c index 7144ae651d3d..4997c1a8b59d 100644 --- a/arch/arm/mach-omap2/omap_hwmod.c +++ b/arch/arm/mach-omap2/omap_hwmod.c @@ -1480,6 +1480,11 @@ static int _reset(struct omap_hwmod *oh) pr_debug("omap_hwmod: %s: resetting\n", oh->name); + /* + * XXX We're not resetting modules with hardreset lines + * automatically here. Should we do this also, or just expect + * those modules to define custom reset functions? + */ ret = (oh->class->reset) ? oh->class->reset(oh) : _ocp_softreset(oh); if (oh->class->sysc) { @@ -1500,7 +1505,7 @@ static int _reset(struct omap_hwmod *oh) */ static int _enable(struct omap_hwmod *oh) { - int r; + int r, i; int hwsup = 0; pr_debug("omap_hwmod: %s: enabling\n", oh->name); @@ -1532,15 +1537,15 @@ static int _enable(struct omap_hwmod *oh) return -EINVAL; } - /* - * If an IP contains only one HW reset line, then de-assert it in order + * If an IP contains HW reset lines, then de-assert them in order * to allow the module state transition. Otherwise the PRCM will return * Intransition status, and the init will failed. */ - if ((oh->_state == _HWMOD_STATE_INITIALIZED || - oh->_state == _HWMOD_STATE_DISABLED) && oh->rst_lines_cnt == 1) - _deassert_hardreset(oh, oh->rst_lines[0].name); + if (oh->_state == _HWMOD_STATE_INITIALIZED || + oh->_state == _HWMOD_STATE_DISABLED) + for (i = 0; i < oh->rst_lines_cnt; i++) + _deassert_hardreset(oh, oh->rst_lines[i].name); /* Mux pins for device runtime if populated */ if (oh->mux && (!oh->mux->enabled || @@ -1687,7 +1692,7 @@ int omap_hwmod_set_ocp_autoidle(struct omap_hwmod *oh, u8 autoidle) */ static int _shutdown(struct omap_hwmod *oh) { - int ret; + int ret, i; u8 prev_state; if (oh->_state != _HWMOD_STATE_IDLE && @@ -1728,12 +1733,8 @@ static int _shutdown(struct omap_hwmod *oh) } /* XXX Should this code also force-disable the optional clocks? */ - /* - * If an IP contains only one HW reset line, then assert it - * after disabling the clocks and before shutting down the IP. - */ - if (oh->rst_lines_cnt == 1) - _assert_hardreset(oh, oh->rst_lines[0].name); + for (i = 0; i < oh->rst_lines_cnt; i++) + _assert_hardreset(oh, oh->rst_lines[i].name); /* Mux pins to safe mode or use populated off mode values */ if (oh->mux) @@ -1786,7 +1787,7 @@ static int _setup(struct omap_hwmod *oh, void *data) * reset asserted. Exit without warning because that behavior is * expected. */ - if ((oh->flags & HWMOD_INIT_NO_RESET) && oh->rst_lines_cnt == 1) + if ((oh->flags & HWMOD_INIT_NO_RESET) && oh->rst_lines_cnt > 0) return 0; r = _enable(oh); -- cgit v1.2.3 From 30e105c000abbac55602b37f4831437bca5487b0 Mon Sep 17 00:00:00 2001 From: Paul Walmsley Date: Thu, 19 Apr 2012 00:49:09 -0600 Subject: ARM: OMAP2+: hwmod: revise the IP block reset process MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Revise the IP block reset process. This patch ensures that the OCP_SYSCONFIG registers are reloaded after a custom reset. Since OCP_SYSCONFIG bits are cleared during reset, they should be reprogrammed unless the IP block is being left in reset. (The only IP blocks that are left in reset are IP blocks with hardreset lines and no custom reset function.) If the IP block is left in reset, then it is inaccessible to the MPU, and an access to the OCP_SYSCONFIG register will cause an abort. This version incorporates comments from Omar Ramirez Luna to skip the OCP_SYSCONFIG access after asserting hardreset lines. This allows the MMU (IOMMU) IP block, which has both hardreset lines and an OCP_SYSCONFIG register. Also, ignore _ocp_softreset() errors if the IP block doesn't include a softreset bit. This is needed since a subsequent patch will start taking the return value of the _reset() function seriously. Signed-off-by: Paul Walmsley Cc: Benoît Cousson Cc: Omar Ramirez Luna --- arch/arm/mach-omap2/omap_hwmod.c | 69 ++++++++++++++++++++++++++-------------- 1 file changed, 46 insertions(+), 23 deletions(-) (limited to 'arch/arm/mach-omap2/omap_hwmod.c') diff --git a/arch/arm/mach-omap2/omap_hwmod.c b/arch/arm/mach-omap2/omap_hwmod.c index 4997c1a8b59d..5b07ad0251d7 100644 --- a/arch/arm/mach-omap2/omap_hwmod.c +++ b/arch/arm/mach-omap2/omap_hwmod.c @@ -2,7 +2,7 @@ * omap_hwmod implementation for OMAP2/3/4 * * Copyright (C) 2009-2011 Nokia Corporation - * Copyright (C) 2011 Texas Instruments, Inc. + * Copyright (C) 2011-2012 Texas Instruments, Inc. * * Paul Walmsley, Benoît Cousson, Kevin Hilman * @@ -1382,9 +1382,9 @@ static int _read_hardreset(struct omap_hwmod *oh, const char *name) * @oh: struct omap_hwmod * * * Resets an omap_hwmod @oh via the OCP_SYSCONFIG bit. hwmod must be - * enabled for this to work. Returns -EINVAL if the hwmod cannot be - * reset this way or if the hwmod is in the wrong state, -ETIMEDOUT if - * the module did not reset in time, or 0 upon success. + * enabled for this to work. Returns -ENOENT if the hwmod cannot be + * reset this way, -EINVAL if the hwmod is in the wrong state, + * -ETIMEDOUT if the module did not reset in time, or 0 upon success. * * In OMAP3 a specific SYSSTATUS register is used to get the reset status. * Starting in OMAP4, some IPs do not have SYSSTATUS registers and instead @@ -1401,7 +1401,7 @@ static int _ocp_softreset(struct omap_hwmod *oh) if (!oh->class->sysc || !(oh->class->sysc->sysc_flags & SYSC_HAS_SOFTRESET)) - return -EINVAL; + return -ENOENT; /* clocks must be on for this operation */ if (oh->_state != _HWMOD_STATE_ENABLED) { @@ -1462,37 +1462,60 @@ dis_opt_clks: * _reset - reset an omap_hwmod * @oh: struct omap_hwmod * * - * Resets an omap_hwmod @oh. The default software reset mechanism for - * most OMAP IP blocks is triggered via the OCP_SYSCONFIG.SOFTRESET - * bit. However, some hwmods cannot be reset via this method: some - * are not targets and therefore have no OCP header registers to - * access; others (like the IVA) have idiosyncratic reset sequences. - * So for these relatively rare cases, custom reset code can be - * supplied in the struct omap_hwmod_class .reset function pointer. - * Passes along the return value from either _reset() or the custom - * reset function - these must return -EINVAL if the hwmod cannot be - * reset this way or if the hwmod is in the wrong state, -ETIMEDOUT if - * the module did not reset in time, or 0 upon success. + * Resets an omap_hwmod @oh. If the module has a custom reset + * function pointer defined, then call it to reset the IP block, and + * pass along its return value to the caller. Otherwise, if the IP + * block has an OCP_SYSCONFIG register with a SOFTRESET bitfield + * associated with it, call a function to reset the IP block via that + * method, and pass along the return value to the caller. Finally, if + * the IP block has some hardreset lines associated with it, assert + * all of those, but do _not_ deassert them. (This is because driver + * authors have expressed an apparent requirement to control the + * deassertion of the hardreset lines themselves.) + * + * The default software reset mechanism for most OMAP IP blocks is + * triggered via the OCP_SYSCONFIG.SOFTRESET bit. However, some + * hwmods cannot be reset via this method. Some are not targets and + * therefore have no OCP header registers to access. Others (like the + * IVA) have idiosyncratic reset sequences. So for these relatively + * rare cases, custom reset code can be supplied in the struct + * omap_hwmod_class .reset function pointer. Passes along the return + * value from either _ocp_softreset() or the custom reset function - + * these must return -EINVAL if the hwmod cannot be reset this way or + * if the hwmod is in the wrong state, -ETIMEDOUT if the module did + * not reset in time, or 0 upon success. */ static int _reset(struct omap_hwmod *oh) { - int ret; + int i, r; pr_debug("omap_hwmod: %s: resetting\n", oh->name); + if (oh->class->reset) { + r = oh->class->reset(oh); + } else { + if (oh->rst_lines_cnt > 0) { + for (i = 0; i < oh->rst_lines_cnt; i++) + _assert_hardreset(oh, oh->rst_lines[i].name); + return 0; + } else { + r = _ocp_softreset(oh); + if (r == -ENOENT) + r = 0; + } + } + /* - * XXX We're not resetting modules with hardreset lines - * automatically here. Should we do this also, or just expect - * those modules to define custom reset functions? + * OCP_SYSCONFIG bits need to be reprogrammed after a + * softreset. The _enable() function should be split to avoid + * the rewrite of the OCP_SYSCONFIG register. */ - ret = (oh->class->reset) ? oh->class->reset(oh) : _ocp_softreset(oh); - if (oh->class->sysc) { _update_sysc_cache(oh); _enable_sysc(oh); } - return ret; + return r; } /** -- cgit v1.2.3 From 381d033a0164afaaac2a1c35bc8bc379052595b2 Mon Sep 17 00:00:00 2001 From: Paul Walmsley Date: Thu, 19 Apr 2012 00:58:22 -0600 Subject: ARM: OMAP2+: hwmod: reorganize and document the initialization process MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Reorganize the code involved in initializing the internal data for each hwmod to make it easier to read and maintain. This involves improving documentation and removing some duplicated and unnecessary code. Signed-off-by: Paul Walmsley Cc: Benoît Cousson --- arch/arm/mach-omap2/omap_hwmod.c | 137 +++++++++++++++++++++++---------------- 1 file changed, 80 insertions(+), 57 deletions(-) (limited to 'arch/arm/mach-omap2/omap_hwmod.c') diff --git a/arch/arm/mach-omap2/omap_hwmod.c b/arch/arm/mach-omap2/omap_hwmod.c index 5b07ad0251d7..503832e20d56 100644 --- a/arch/arm/mach-omap2/omap_hwmod.c +++ b/arch/arm/mach-omap2/omap_hwmod.c @@ -1768,6 +1768,56 @@ static int _shutdown(struct omap_hwmod *oh) return 0; } +/** + * _init_mpu_rt_base - populate the virtual address for a hwmod + * @oh: struct omap_hwmod * to locate the virtual address + * + * Cache the virtual address used by the MPU to access this IP block's + * registers. This address is needed early so the OCP registers that + * are part of the device's address space can be ioremapped properly. + * No return value. + */ +static void __init _init_mpu_rt_base(struct omap_hwmod *oh, void *data) +{ + if (oh->_int_flags & _HWMOD_NO_MPU_PORT) + return; + + oh->_mpu_rt_va = _find_mpu_rt_base(oh, oh->_mpu_port_index); +} + +/** + * _init - initialize internal data for the hwmod @oh + * @oh: struct omap_hwmod * + * @n: (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 + * registered at this point. This is the first of two phases for + * hwmod initialization. Code called here does not touch any hardware + * registers, it simply prepares internal data structures. Returns 0 + * upon success or if the hwmod isn't registered, or -EINVAL upon + * failure. + */ +static int __init _init(struct omap_hwmod *oh, void *data) +{ + int r; + + if (oh->_state != _HWMOD_STATE_REGISTERED) + return 0; + + _init_mpu_rt_base(oh, NULL); + + r = _init_clocks(oh, NULL); + if (IS_ERR_VALUE(r)) { + WARN(1, "omap_hwmod: %s: couldn't init clocks\n", oh->name); + return -EINVAL; + } + + oh->_state = _HWMOD_STATE_INITIALIZED; + + return 0; +} + /** * _setup - do initial configuration of omap_hwmod * @oh: struct omap_hwmod * @@ -1780,7 +1830,7 @@ static int _setup(struct omap_hwmod *oh, void *data) int i, r; u8 postsetup_state; - if (oh->_state != _HWMOD_STATE_CLKS_INITED) + if (oh->_state != _HWMOD_STATE_INITIALIZED) return 0; /* Set iclk autoidle mode */ @@ -2052,96 +2102,69 @@ int __init omap_hwmod_register(struct omap_hwmod **ohs) return 0; } -/* - * _populate_mpu_rt_base - populate the virtual address for a hwmod +/** + * _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) * - * Must be called only from omap_hwmod_setup_*() so ioremap works properly. - * Assumes the caller takes care of locking if needed. + * If the hwmod data corresponding to the MPU subsystem IP block + * hasn't been initialized and set up yet, do so now. This must be + * done first since sleep dependencies may be added from other hwmods + * to the MPU. Intended to be called only by omap_hwmod_setup*(). No + * return value. */ -static int __init _populate_mpu_rt_base(struct omap_hwmod *oh, void *data) +static void __init _ensure_mpu_hwmod_is_setup(struct omap_hwmod *oh) { - if (oh->_state != _HWMOD_STATE_REGISTERED) - return 0; - - if (oh->_int_flags & _HWMOD_NO_MPU_PORT) - return 0; - - oh->_mpu_rt_va = _find_mpu_rt_base(oh, oh->_mpu_port_index); - - return 0; + if (!mpu_oh || mpu_oh->_state == _HWMOD_STATE_UNKNOWN) + pr_err("omap_hwmod: %s: MPU initiator hwmod %s not yet registered\n", + __func__, MPU_INITIATOR_NAME); + else if (mpu_oh->_state == _HWMOD_STATE_REGISTERED && oh != mpu_oh) + omap_hwmod_setup_one(MPU_INITIATOR_NAME); } /** * omap_hwmod_setup_one - set up a single hwmod * @oh_name: const char * name of the already-registered hwmod to set up * - * Must be called after omap2_clk_init(). Resolves the struct clk - * names to struct clk pointers for each registered omap_hwmod. Also - * calls _setup() on each hwmod. Returns -EINVAL upon error or 0 upon - * success. + * Initialize and set up a single hwmod. Intended to be used for a + * small number of early devices, such as the timer IP blocks used for + * the scheduler clock. Must be called after omap2_clk_init(). + * Resolves the struct clk names to struct clk pointers for each + * 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) { struct omap_hwmod *oh; - int r; pr_debug("omap_hwmod: %s: %s\n", oh_name, __func__); - if (!mpu_oh) { - pr_err("omap_hwmod: %s: cannot setup_one: MPU initiator hwmod %s not yet registered\n", - oh_name, MPU_INITIATOR_NAME); - return -EINVAL; - } - oh = _lookup(oh_name); if (!oh) { WARN(1, "omap_hwmod: %s: hwmod not yet registered\n", oh_name); return -EINVAL; } - if (mpu_oh->_state == _HWMOD_STATE_REGISTERED && oh != mpu_oh) - omap_hwmod_setup_one(MPU_INITIATOR_NAME); - - r = _populate_mpu_rt_base(oh, NULL); - if (IS_ERR_VALUE(r)) { - WARN(1, "omap_hwmod: %s: couldn't set mpu_rt_base\n", oh_name); - return -EINVAL; - } - - r = _init_clocks(oh, NULL); - if (IS_ERR_VALUE(r)) { - WARN(1, "omap_hwmod: %s: couldn't init clocks\n", oh_name); - return -EINVAL; - } + _ensure_mpu_hwmod_is_setup(oh); + _init(oh, NULL); _setup(oh, NULL); return 0; } /** - * omap_hwmod_setup - do some post-clock framework initialization + * omap_hwmod_setup_all - set up all registered IP blocks * - * Must be called after omap2_clk_init(). Resolves the struct clk names - * to struct clk pointers for each registered omap_hwmod. Also calls - * _setup() on each hwmod. Returns 0 upon success. + * Initialize and set up all IP blocks registered with the hwmod code. + * Must be called after omap2_clk_init(). Resolves the struct clk + * names to struct clk pointers for each registered omap_hwmod. Also + * calls _setup() on each hwmod. Returns 0 upon success. */ static int __init omap_hwmod_setup_all(void) { - int r; - - if (!mpu_oh) { - pr_err("omap_hwmod: %s: MPU initiator hwmod %s not yet registered\n", - __func__, MPU_INITIATOR_NAME); - return -EINVAL; - } - - r = omap_hwmod_for_each(_populate_mpu_rt_base, NULL); - - r = omap_hwmod_for_each(_init_clocks, NULL); - WARN(IS_ERR_VALUE(r), - "omap_hwmod: %s: _init_clocks failed\n", __func__); + _ensure_mpu_hwmod_is_setup(NULL); + omap_hwmod_for_each(_init, NULL); omap_hwmod_for_each(_setup, NULL); return 0; -- cgit v1.2.3 From 64813c3fa68fc3e93e99187d313126710d7c4b0d Mon Sep 17 00:00:00 2001 From: Paul Walmsley Date: Wed, 18 Apr 2012 19:10:03 -0600 Subject: ARM: OMAP2+: hwmod: reorganize and document the reset and configuration process MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Reorganize the code involved in resetting and configuring an IP block to make it easier to read and maintain. This involves improving documentation, splitting some large functions up into smaller ones to better conform with Documentation/CodingStyle, and removing some unnecessary code. Signed-off-by: Paul Walmsley Cc: Benoît Cousson --- arch/arm/mach-omap2/omap_hwmod.c | 152 ++++++++++++++++++++++++++++++--------- 1 file changed, 120 insertions(+), 32 deletions(-) (limited to 'arch/arm/mach-omap2/omap_hwmod.c') diff --git a/arch/arm/mach-omap2/omap_hwmod.c b/arch/arm/mach-omap2/omap_hwmod.c index 503832e20d56..6c6d31b432d2 100644 --- a/arch/arm/mach-omap2/omap_hwmod.c +++ b/arch/arm/mach-omap2/omap_hwmod.c @@ -1534,10 +1534,9 @@ static int _enable(struct omap_hwmod *oh) pr_debug("omap_hwmod: %s: enabling\n", oh->name); /* - * hwmods with HWMOD_INIT_NO_IDLE flag set are left - * in enabled state at init. - * Now that someone is really trying to enable them, - * just ensure that the hwmod mux is set. + * hwmods with HWMOD_INIT_NO_IDLE flag set are left in enabled + * state at init. Now that someone is really trying to enable + * them, just ensure that the hwmod mux is set. */ if (oh->_int_flags & _HWMOD_SKIP_ENABLE) { /* @@ -1819,46 +1818,60 @@ static int __init _init(struct omap_hwmod *oh, void *data) } /** - * _setup - do initial configuration of omap_hwmod + * _setup_iclk_autoidle - configure an IP block's interface clocks * @oh: struct omap_hwmod * * - * Writes the CLOCKACTIVITY bits @clockact to the hwmod @oh - * OCP_SYSCONFIG register. Returns 0. + * Set up the module's interface clocks. XXX This function is still mostly + * a stub; implementing this properly requires iclk autoidle usecounting in + * the clock code. No return value. */ -static int _setup(struct omap_hwmod *oh, void *data) +static void __init _setup_iclk_autoidle(struct omap_hwmod *oh) { - int i, r; - u8 postsetup_state; + int i; if (oh->_state != _HWMOD_STATE_INITIALIZED) - return 0; + return; - /* Set iclk autoidle mode */ - if (oh->slaves_cnt > 0) { - for (i = 0; i < oh->slaves_cnt; i++) { - struct omap_hwmod_ocp_if *os = oh->slaves[i]; - struct clk *c = os->_clk; + for (i = 0; i < oh->slaves_cnt; i++) { + struct omap_hwmod_ocp_if *os = oh->slaves[i]; + struct clk *c = os->_clk; - if (!c) - continue; + if (!c) + continue; - if (os->flags & OCPIF_SWSUP_IDLE) { - /* XXX omap_iclk_deny_idle(c); */ - } else { - /* XXX omap_iclk_allow_idle(c); */ - clk_enable(c); - } + if (os->flags & OCPIF_SWSUP_IDLE) { + /* XXX omap_iclk_deny_idle(c); */ + } else { + /* XXX omap_iclk_allow_idle(c); */ + clk_enable(c); } } - oh->_state = _HWMOD_STATE_INITIALIZED; + return; +} + +/** + * _setup_reset - reset an IP block during the setup process + * @oh: struct omap_hwmod * + * + * Reset the IP block corresponding to the hwmod @oh during the setup + * process. The IP block is first enabled so it can be successfully + * reset. Returns 0 upon success or a negative error code upon + * failure. + */ +static int __init _setup_reset(struct omap_hwmod *oh) +{ + int r; + + if (oh->_state != _HWMOD_STATE_INITIALIZED) + return -EINVAL; /* * In the case of hwmod with hardreset that should not be * de-assert at boot time, we have to keep the module * initialized, because we cannot enable it properly with the - * reset asserted. Exit without warning because that behavior is - * expected. + * reset asserted. Exit without warning because that behavior + * is expected. */ if ((oh->flags & HWMOD_INIT_NO_RESET) && oh->rst_lines_cnt > 0) return 0; @@ -1871,7 +1884,53 @@ static int _setup(struct omap_hwmod *oh, void *data) } if (!(oh->flags & HWMOD_INIT_NO_RESET)) - _reset(oh); + r = _reset(oh); + + return r; +} + +/** + * _setup_postsetup - transition to the appropriate state after _setup + * @oh: struct omap_hwmod * + * + * Place an IP block represented by @oh into a "post-setup" state -- + * either IDLE, ENABLED, or DISABLED. ("post-setup" simply means that + * this function is called at the end of _setup().) The postsetup + * state for an IP block can be changed by calling + * omap_hwmod_enter_postsetup_state() early in the boot process, + * before one of the omap_hwmod_setup*() functions are called for the + * IP block. + * + * The IP block stays in this state until a PM runtime-based driver is + * loaded for that IP block. A post-setup state of IDLE is + * appropriate for almost all IP blocks with runtime PM-enabled + * drivers, since those drivers are able to enable the IP block. A + * post-setup state of ENABLED is appropriate for kernels with PM + * runtime disabled. The DISABLED state is appropriate for unusual IP + * blocks such as the MPU WDTIMER on kernels without WDTIMER drivers + * included, since the WDTIMER starts running on reset and will reset + * the MPU if left active. + * + * This post-setup mechanism is deprecated. Once all of the OMAP + * drivers have been converted to use PM runtime, and all of the IP + * block data and interconnect data is available to the hwmod code, it + * should be possible to replace this mechanism with a "lazy reset" + * arrangement. In a "lazy reset" setup, each IP block is enabled + * when the driver first probes, then all remaining IP blocks without + * drivers are either shut down or enabled after the drivers have + * loaded. However, this cannot take place until the above + * preconditions have been met, since otherwise the late reset code + * has no way of knowing which IP blocks are in use by drivers, and + * which ones are unused. + * + * No return value. + */ +static void __init _setup_postsetup(struct omap_hwmod *oh) +{ + u8 postsetup_state; + + if (oh->rst_lines_cnt > 0) + return; postsetup_state = oh->_postsetup_state; if (postsetup_state == _HWMOD_STATE_UNKNOWN) @@ -1895,6 +1954,35 @@ static int _setup(struct omap_hwmod *oh, void *data) WARN(1, "hwmod: %s: unknown postsetup state %d! defaulting to enabled\n", oh->name, postsetup_state); + return; +} + +/** + * _setup - prepare IP block hardware for use + * @oh: struct omap_hwmod * + * @n: (unused, pass NULL) + * + * Configure the IP block represented by @oh. This may include + * enabling the IP block, resetting it, and placing it into a + * post-setup state, depending on the type of IP block and applicable + * flags. IP blocks are reset to prevent any previous configuration + * by the bootloader or previous operating system from interfering + * with power management or other parts of the system. The reset can + * be avoided; see omap_hwmod_no_setup_reset(). This is the second of + * two phases for hwmod initialization. Code called here generally + * affects the IP block hardware, or system integration hardware + * associated with the IP block. Returns 0. + */ +static int __init _setup(struct omap_hwmod *oh, void *data) +{ + if (oh->_state != _HWMOD_STATE_INITIALIZED) + return 0; + + _setup_iclk_autoidle(oh); + + if (!_setup_reset(oh)) + _setup_postsetup(oh); + return 0; } @@ -2700,10 +2788,10 @@ int omap_hwmod_for_each_by_class(const char *classname, * @state: state that _setup() should leave the hwmod in * * Sets the hwmod state that @oh will enter at the end of _setup() - * (called by omap_hwmod_setup_*()). Only valid to call between - * calling omap_hwmod_register() and omap_hwmod_setup_*(). Returns - * 0 upon success or -EINVAL if there is a problem with the arguments - * or if the hwmod is in the wrong state. + * (called by omap_hwmod_setup_*()). See also the documentation + * for _setup_postsetup(), above. Returns 0 upon success or + * -EINVAL if there is a problem with the arguments or if the hwmod is + * in the wrong state. */ int omap_hwmod_set_postsetup_state(struct omap_hwmod *oh, u8 state) { -- cgit v1.2.3 From 747834ab83475f47878c68954d913e27124e4391 Mon Sep 17 00:00:00 2001 From: Paul Walmsley Date: Wed, 18 Apr 2012 19:10:04 -0600 Subject: ARM: OMAP2+: hwmod: revise hardreset behavior MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Change the way that hardreset lines are handled by the hwmod code. Hardreset lines are generally associated with initiator IP blocks. Prior to this change, the hwmod code expected to control hardreset lines itself, asserting them on shutdown and deasserting them upon enable. But driver authors inside TI have commented to us that their drivers require direct control over these lines. Unfortunately, these drivers haven't been posted publicly yet, so it's hard to determine exactly what is needed, a priori. This change attempts to set forth some reasonable semantics that should be an improvement over the current code. The semantics implemented by this patch are as follows: - If the hwmod is not marked with HWMOD_INIT_NO_RESET, then assert all associated hardreset lines during IP block setup. This is intended to place the IP blocks into a known state that will not interfere with other devices during kernel boot. - IP blocks with hardreset lines will not be automatically enabled or idled during setup. Instead, they will be left in the INITIALIZED state. - When the hwmod code is asked to enable, idle, or shutdown an IP block with asserted hardreset lines, the hwmod code will do nothing. The driver integration code must do the remaining work needed to control these IP blocks. Once this driver integration code is posted to the lists, hopefully we can consolidate it and move it inside the hwmod code. Custom reset functions for IP blocks with hardreset lines still should be supported and are strongly endorsed. It is intended that every subsystem with hardreset lines should have a custom reset function that can place their subsystem into quiescent idle with the hardreset lines deasserted. This reverts most of commit 5365efbe29250a227502256cc912351fe2157b42 ("OMAP: hwmod: Add hardreset management support"). Later code reorganizations caused the sequencing of the code from this patch to be changed, anyway. Signed-off-by: Paul Walmsley Cc: Benoît Cousson --- arch/arm/mach-omap2/omap_hwmod.c | 139 +++++++++++++++++++++++---------------- 1 file changed, 83 insertions(+), 56 deletions(-) (limited to 'arch/arm/mach-omap2/omap_hwmod.c') diff --git a/arch/arm/mach-omap2/omap_hwmod.c b/arch/arm/mach-omap2/omap_hwmod.c index 6c6d31b432d2..bd9fc10ea737 100644 --- a/arch/arm/mach-omap2/omap_hwmod.c +++ b/arch/arm/mach-omap2/omap_hwmod.c @@ -780,39 +780,6 @@ static int _omap4_wait_target_disable(struct omap_hwmod *oh) oh->prcm.omap4.clkctrl_offs); } -/** - * _omap4_disable_module - enable CLKCTRL modulemode on OMAP4 - * @oh: struct omap_hwmod * - * - * Disable the PRCM module mode related to the hwmod @oh. - * Return EINVAL if the modulemode is not supported and 0 in case of success. - */ -static int _omap4_disable_module(struct omap_hwmod *oh) -{ - int v; - - /* The module mode does not exist prior OMAP4 */ - if (!cpu_is_omap44xx()) - return -EINVAL; - - if (!oh->clkdm || !oh->prcm.omap4.modulemode) - return -EINVAL; - - pr_debug("omap_hwmod: %s: %s\n", oh->name, __func__); - - omap4_cminst_module_disable(oh->clkdm->prcm_partition, - oh->clkdm->cm_inst, - oh->clkdm->clkdm_offs, - oh->prcm.omap4.clkctrl_offs); - - v = _omap4_wait_target_disable(oh); - if (v) - pr_warn("omap_hwmod: %s: _wait_target_disable failed\n", - oh->name); - - return 0; -} - /** * _count_mpu_irqs - count the number of MPU IRQ lines associated with @oh * @oh: struct omap_hwmod *oh @@ -1377,6 +1344,66 @@ static int _read_hardreset(struct omap_hwmod *oh, const char *name) } } +/** + * _are_any_hardreset_lines_asserted - return true if part of @oh is hard-reset + * @oh: struct omap_hwmod * + * + * If any hardreset line associated with @oh is asserted, then return true. + * Otherwise, if @oh has no hardreset lines associated with it, or if + * no hardreset lines associated with @oh are asserted, then return false. + * This function is used to avoid executing some parts of the IP block + * enable/disable sequence if a hardreset line is set. + */ +static bool _are_any_hardreset_lines_asserted(struct omap_hwmod *oh) +{ + int i; + + if (oh->rst_lines_cnt == 0) + return false; + + for (i = 0; i < oh->rst_lines_cnt; i++) + if (_read_hardreset(oh, oh->rst_lines[i].name) > 0) + return true; + + return false; +} + +/** + * _omap4_disable_module - enable CLKCTRL modulemode on OMAP4 + * @oh: struct omap_hwmod * + * + * Disable the PRCM module mode related to the hwmod @oh. + * Return EINVAL if the modulemode is not supported and 0 in case of success. + */ +static int _omap4_disable_module(struct omap_hwmod *oh) +{ + int v; + + /* The module mode does not exist prior OMAP4 */ + if (!cpu_is_omap44xx()) + return -EINVAL; + + if (!oh->clkdm || !oh->prcm.omap4.modulemode) + return -EINVAL; + + pr_debug("omap_hwmod: %s: %s\n", oh->name, __func__); + + omap4_cminst_module_disable(oh->clkdm->prcm_partition, + oh->clkdm->cm_inst, + oh->clkdm->clkdm_offs, + oh->prcm.omap4.clkctrl_offs); + + if (_are_any_hardreset_lines_asserted(oh)) + return 0; + + v = _omap4_wait_target_disable(oh); + if (v) + pr_warn("omap_hwmod: %s: _wait_target_disable failed\n", + oh->name); + + return 0; +} + /** * _ocp_softreset - reset an omap_hwmod via the OCP_SYSCONFIG bit * @oh: struct omap_hwmod * @@ -1528,7 +1555,7 @@ static int _reset(struct omap_hwmod *oh) */ static int _enable(struct omap_hwmod *oh) { - int r, i; + int r; int hwsup = 0; pr_debug("omap_hwmod: %s: enabling\n", oh->name); @@ -1560,14 +1587,16 @@ static int _enable(struct omap_hwmod *oh) } /* - * If an IP contains HW reset lines, then de-assert them in order - * to allow the module state transition. Otherwise the PRCM will return - * Intransition status, and the init will failed. + * If an IP block contains HW reset lines and any of them are + * asserted, we let integration code associated with that + * block handle the enable. We've received very little + * information on what those driver authors need, and until + * detailed information is provided and the driver code is + * posted to the public lists, this is probably the best we + * can do. */ - if (oh->_state == _HWMOD_STATE_INITIALIZED || - oh->_state == _HWMOD_STATE_DISABLED) - for (i = 0; i < oh->rst_lines_cnt; i++) - _deassert_hardreset(oh, oh->rst_lines[i].name); + if (_are_any_hardreset_lines_asserted(oh)) + return 0; /* Mux pins for device runtime if populated */ if (oh->mux && (!oh->mux->enabled || @@ -1642,6 +1671,9 @@ static int _idle(struct omap_hwmod *oh) return -EINVAL; } + if (_are_any_hardreset_lines_asserted(oh)) + return 0; + if (oh->class->sysc) _idle_sysc(oh); _del_initiator_dep(oh, mpu_oh); @@ -1724,6 +1756,9 @@ static int _shutdown(struct omap_hwmod *oh) return -EINVAL; } + if (_are_any_hardreset_lines_asserted(oh)) + return 0; + pr_debug("omap_hwmod: %s: disabling\n", oh->name); if (oh->class->pre_shutdown) { @@ -1866,21 +1901,13 @@ static int __init _setup_reset(struct omap_hwmod *oh) if (oh->_state != _HWMOD_STATE_INITIALIZED) return -EINVAL; - /* - * In the case of hwmod with hardreset that should not be - * de-assert at boot time, we have to keep the module - * initialized, because we cannot enable it properly with the - * reset asserted. Exit without warning because that behavior - * is expected. - */ - if ((oh->flags & HWMOD_INIT_NO_RESET) && oh->rst_lines_cnt > 0) - return 0; - - r = _enable(oh); - if (r) { - pr_warning("omap_hwmod: %s: cannot be enabled (%d)\n", - oh->name, oh->_state); - return 0; + if (oh->rst_lines_cnt == 0) { + r = _enable(oh); + if (r) { + pr_warning("omap_hwmod: %s: cannot be enabled for reset (%d)\n", + oh->name, oh->_state); + return -EINVAL; + } } if (!(oh->flags & HWMOD_INIT_NO_RESET)) -- cgit v1.2.3 From c9aafd23d6c1b466f37f554e9916886e7d4645d0 Mon Sep 17 00:00:00 2001 From: Paul Walmsley Date: Wed, 18 Apr 2012 19:10:05 -0600 Subject: ARM: OMAP2+: hwmod: provide a function to return the address space of the MPU RT MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit A subsequent patch will need to know the struct omap_hwmod_addr_space record corresponding to the module's register target, used by the MPU. So, convert _find_mpu_rt_base() into _find_mpu_rt_addr_space(). Then modify its sole current user, _populate_mpu_rt_base(), to extract the MPU RT base address itself from the struct omap_hwmod_addr_space record. Signed-off-by: Paul Walmsley Cc: Benoît Cousson --- arch/arm/mach-omap2/omap_hwmod.c | 55 ++++++++++++++++++++++------------------ 1 file changed, 31 insertions(+), 24 deletions(-) (limited to 'arch/arm/mach-omap2/omap_hwmod.c') diff --git a/arch/arm/mach-omap2/omap_hwmod.c b/arch/arm/mach-omap2/omap_hwmod.c index bd9fc10ea737..52c69d265f7c 100644 --- a/arch/arm/mach-omap2/omap_hwmod.c +++ b/arch/arm/mach-omap2/omap_hwmod.c @@ -884,24 +884,22 @@ static int __init _find_mpu_port_index(struct omap_hwmod *oh) } /** - * _find_mpu_rt_base - find hwmod register target base addr accessible by MPU + * _find_mpu_rt_addr_space - return MPU register target address space for @oh * @oh: struct omap_hwmod * * - * Return the virtual address of the base of the register target of - * device @oh, or NULL on error. + * Returns a pointer to the struct omap_hwmod_addr_space record representing + * the register target MPU address space; or returns NULL upon error. */ -static void __iomem * __init _find_mpu_rt_base(struct omap_hwmod *oh, u8 index) +static struct omap_hwmod_addr_space * __init _find_mpu_rt_addr_space(struct omap_hwmod *oh) { struct omap_hwmod_ocp_if *os; struct omap_hwmod_addr_space *mem; - int i = 0, found = 0; - void __iomem *va_start; + int found = 0, i = 0; - if (!oh || oh->slaves_cnt == 0) + if (!oh || oh->_int_flags & _HWMOD_NO_MPU_PORT || oh->slaves_cnt == 0) return NULL; - os = oh->slaves[index]; - + os = oh->slaves[oh->_mpu_port_index]; if (!os->addr) return NULL; @@ -911,20 +909,7 @@ static void __iomem * __init _find_mpu_rt_base(struct omap_hwmod *oh, u8 index) found = 1; } while (!found && mem->pa_start != mem->pa_end); - if (found) { - va_start = ioremap(mem->pa_start, mem->pa_end - mem->pa_start); - if (!va_start) { - pr_err("omap_hwmod: %s: Could not ioremap\n", oh->name); - return NULL; - } - pr_debug("omap_hwmod: %s: MPU register target at va %p\n", - oh->name, va_start); - } else { - pr_debug("omap_hwmod: %s: no MPU register target found\n", - oh->name); - } - - return (found) ? va_start : NULL; + return (found) ? mem : NULL; } /** @@ -1813,10 +1798,32 @@ static int _shutdown(struct omap_hwmod *oh) */ static void __init _init_mpu_rt_base(struct omap_hwmod *oh, void *data) { + struct omap_hwmod_addr_space *mem; + void __iomem *va_start; + + if (!oh) + return; + if (oh->_int_flags & _HWMOD_NO_MPU_PORT) return; - oh->_mpu_rt_va = _find_mpu_rt_base(oh, oh->_mpu_port_index); + mem = _find_mpu_rt_addr_space(oh); + if (!mem) { + pr_debug("omap_hwmod: %s: no MPU register target found\n", + oh->name); + return; + } + + va_start = ioremap(mem->pa_start, mem->pa_end - mem->pa_start); + if (!va_start) { + pr_err("omap_hwmod: %s: Could not ioremap\n", oh->name); + return; + } + + pr_debug("omap_hwmod: %s: MPU register target at va %p\n", + oh->name, va_start); + + oh->_mpu_rt_va = va_start; } /** -- cgit v1.2.3 From 5e8370f1fa01bf232ca4770c6d81bbf42437d2a3 Mon Sep 17 00:00:00 2001 From: Paul Walmsley Date: Wed, 18 Apr 2012 19:10:06 -0600 Subject: ARM: OMAP2+: hwmod: add omap_hwmod_get_resource_byname() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The timer integration code pokes around in hwmod data structures. Those data structures are about to change. Define a function, omap_hwmod_get_resource_byname(), for the timer integration code to use instead. The original patch has been changed to use struct resource by Tony's request, although the caller of this function should not be a driver._ Platform drivers should get their data through the regular platform_* functions; DT drivers through the appropriate of_* functions. This a function is only for use by OMAP core code in arch/arm/*omap*. Signed-off-by: Paul Walmsley Cc: Benoît Cousson Cc: Tony Lindgren --- arch/arm/mach-omap2/omap_hwmod.c | 208 +++++++++++++++++++++++++++ arch/arm/plat-omap/include/plat/omap_hwmod.h | 2 + 2 files changed, 210 insertions(+) (limited to 'arch/arm/mach-omap2/omap_hwmod.c') diff --git a/arch/arm/mach-omap2/omap_hwmod.c b/arch/arm/mach-omap2/omap_hwmod.c index 52c69d265f7c..230119756504 100644 --- a/arch/arm/mach-omap2/omap_hwmod.c +++ b/arch/arm/mach-omap2/omap_hwmod.c @@ -849,6 +849,147 @@ static int _count_ocp_if_addr_spaces(struct omap_hwmod_ocp_if *os) return i-1; } +/** + * _get_mpu_irq_by_name - fetch MPU interrupt line number by name + * @oh: struct omap_hwmod * to operate on + * @name: pointer to the name of the MPU interrupt number to fetch (optional) + * @irq: pointer to an unsigned int to store the MPU IRQ number to + * + * Retrieve a MPU hardware IRQ line number named by @name associated + * with the IP block pointed to by @oh. The IRQ number will be filled + * into the address pointed to by @dma. When @name is non-null, the + * IRQ line number associated with the named entry will be returned. + * If @name is null, the first matching entry will be returned. Data + * order is not meaningful in hwmod data, so callers are strongly + * encouraged to use a non-null @name whenever possible to avoid + * unpredictable effects if hwmod data is later added that causes data + * ordering to change. Returns 0 upon success or a negative error + * code upon error. + */ +static int _get_mpu_irq_by_name(struct omap_hwmod *oh, const char *name, + unsigned int *irq) +{ + int i; + bool found = false; + + if (!oh->mpu_irqs) + return -ENOENT; + + i = 0; + while (oh->mpu_irqs[i].irq != -1) { + if (name == oh->mpu_irqs[i].name || + !strcmp(name, oh->mpu_irqs[i].name)) { + found = true; + break; + } + i++; + } + + if (!found) + return -ENOENT; + + *irq = oh->mpu_irqs[i].irq; + + return 0; +} + +/** + * _get_sdma_req_by_name - fetch SDMA request line ID by name + * @oh: struct omap_hwmod * to operate on + * @name: pointer to the name of the SDMA request line to fetch (optional) + * @dma: pointer to an unsigned int to store the request line ID to + * + * Retrieve an SDMA request line ID named by @name on the IP block + * pointed to by @oh. The ID will be filled into the address pointed + * to by @dma. When @name is non-null, the request line ID associated + * with the named entry will be returned. If @name is null, the first + * matching entry will be returned. Data order is not meaningful in + * hwmod data, so callers are strongly encouraged to use a non-null + * @name whenever possible to avoid unpredictable effects if hwmod + * data is later added that causes data ordering to change. Returns 0 + * upon success or a negative error code upon error. + */ +static int _get_sdma_req_by_name(struct omap_hwmod *oh, const char *name, + unsigned int *dma) +{ + int i; + bool found = false; + + if (!oh->sdma_reqs) + return -ENOENT; + + i = 0; + while (oh->sdma_reqs[i].dma_req != -1) { + if (name == oh->sdma_reqs[i].name || + !strcmp(name, oh->sdma_reqs[i].name)) { + found = true; + break; + } + i++; + } + + if (!found) + return -ENOENT; + + *dma = oh->sdma_reqs[i].dma_req; + + return 0; +} + +/** + * _get_addr_space_by_name - fetch address space start & end by name + * @oh: struct omap_hwmod * to operate on + * @name: pointer to the name of the address space to fetch (optional) + * @pa_start: pointer to a u32 to store the starting address to + * @pa_end: pointer to a u32 to store the ending address to + * + * Retrieve address space start and end addresses for the IP block + * pointed to by @oh. The data will be filled into the addresses + * pointed to by @pa_start and @pa_end. When @name is non-null, the + * address space data associated with the named entry will be + * returned. If @name is null, the first matching entry will be + * returned. Data order is not meaningful in hwmod data, so callers + * are strongly encouraged to use a non-null @name whenever possible + * to avoid unpredictable effects if hwmod data is later added that + * causes data ordering to change. Returns 0 upon success or a + * negative error code upon error. + */ +static int _get_addr_space_by_name(struct omap_hwmod *oh, const char *name, + u32 *pa_start, u32 *pa_end) +{ + int i, j; + struct omap_hwmod_ocp_if *os; + bool found = false; + + for (i = 0; i < oh->slaves_cnt; i++) { + os = oh->slaves[i]; + + if (!os->addr) + return -ENOENT; + + j = 0; + while (os->addr[j].pa_start != os->addr[j].pa_end) { + if (name == os->addr[j].name || + !strcmp(name, os->addr[j].name)) { + found = true; + break; + } + j++; + } + + if (found) + break; + } + + if (!found) + return -ENOENT; + + *pa_start = os->addr[j].pa_start; + *pa_end = os->addr[j].pa_end; + + return 0; +} + /** * _find_mpu_port_index - find hwmod OCP slave port ID intended for MPU use * @oh: struct omap_hwmod * @@ -2443,6 +2584,10 @@ int omap_hwmod_reset(struct omap_hwmod *oh) return r; } +/* + * IP block data retrieval functions + */ + /** * omap_hwmod_count_resources - count number of struct resources needed by hwmod * @oh: struct omap_hwmod * @@ -2525,6 +2670,69 @@ int omap_hwmod_fill_resources(struct omap_hwmod *oh, struct resource *res) return r; } +/** + * omap_hwmod_get_resource_byname - fetch IP block integration data by name + * @oh: struct omap_hwmod * to operate on + * @type: one of the IORESOURCE_* constants from include/linux/ioport.h + * @name: pointer to the name of the data to fetch (optional) + * @rsrc: pointer to a struct resource, allocated by the caller + * + * Retrieve MPU IRQ, SDMA request line, or address space start/end + * data for the IP block pointed to by @oh. The data will be filled + * into a struct resource record pointed to by @rsrc. The struct + * resource must be allocated by the caller. When @name is non-null, + * the data associated with the matching entry in the IRQ/SDMA/address + * space hwmod data arrays will be returned. If @name is null, the + * first array entry will be returned. Data order is not meaningful + * in hwmod data, so callers are strongly encouraged to use a non-null + * @name whenever possible to avoid unpredictable effects if hwmod + * data is later added that causes data ordering to change. This + * function is only intended for use by OMAP core code. Device + * drivers should not call this function - the appropriate bus-related + * data accessor functions should be used instead. Returns 0 upon + * success or a negative error code upon error. + */ +int omap_hwmod_get_resource_byname(struct omap_hwmod *oh, unsigned int type, + const char *name, struct resource *rsrc) +{ + int r; + unsigned int irq, dma; + u32 pa_start, pa_end; + + if (!oh || !rsrc) + return -EINVAL; + + if (type == IORESOURCE_IRQ) { + r = _get_mpu_irq_by_name(oh, name, &irq); + if (r) + return r; + + rsrc->start = irq; + rsrc->end = irq; + } else if (type == IORESOURCE_DMA) { + r = _get_sdma_req_by_name(oh, name, &dma); + if (r) + return r; + + rsrc->start = dma; + rsrc->end = dma; + } else if (type == IORESOURCE_MEM) { + r = _get_addr_space_by_name(oh, name, &pa_start, &pa_end); + if (r) + return r; + + rsrc->start = pa_start; + rsrc->end = pa_end; + } else { + return -EINVAL; + } + + rsrc->flags = type; + rsrc->name = name; + + return 0; +} + /** * omap_hwmod_get_pwrdm - return pointer to this module's main powerdomain * @oh: struct omap_hwmod * diff --git a/arch/arm/plat-omap/include/plat/omap_hwmod.h b/arch/arm/plat-omap/include/plat/omap_hwmod.h index 3f26db4ee8e6..062a31d438cd 100644 --- a/arch/arm/plat-omap/include/plat/omap_hwmod.h +++ b/arch/arm/plat-omap/include/plat/omap_hwmod.h @@ -581,6 +581,8 @@ int omap_hwmod_softreset(struct omap_hwmod *oh); int omap_hwmod_count_resources(struct omap_hwmod *oh); int omap_hwmod_fill_resources(struct omap_hwmod *oh, struct resource *res); +int omap_hwmod_get_resource_byname(struct omap_hwmod *oh, unsigned int type, + const char *name, struct resource *res); struct powerdomain *omap_hwmod_get_pwrdm(struct omap_hwmod *oh); void __iomem *omap_hwmod_get_mpu_rt_va(struct omap_hwmod *oh); -- cgit v1.2.3 From 2d6141baf15df188283ada7c0fa04679c4fcf1c7 Mon Sep 17 00:00:00 2001 From: Paul Walmsley Date: Thu, 19 Apr 2012 04:04:27 -0600 Subject: ARM: OMAP2+: hwmod: add _find_mpu_rt_port() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Most IP blocks on the OMAP SoC have an interconnect link that is intended to be used by the MPU to communicate with the IP block. Several parts of the hwmod code need to be able to identify this link. Currently, this is open-coded. However, future patches will change the way that interconnect links are represented and will make identifying the link more complex. So to avoid code duplication, this patch centralizes the MPU port link identification code into a new function, _find_mpu_rt_port(). Signed-off-by: Paul Walmsley Cc: Benoît Cousson --- arch/arm/mach-omap2/omap_hwmod.c | 39 +++++++++++++++++++++++++++++---------- 1 file changed, 29 insertions(+), 10 deletions(-) (limited to 'arch/arm/mach-omap2/omap_hwmod.c') diff --git a/arch/arm/mach-omap2/omap_hwmod.c b/arch/arm/mach-omap2/omap_hwmod.c index 230119756504..241c663a8f62 100644 --- a/arch/arm/mach-omap2/omap_hwmod.c +++ b/arch/arm/mach-omap2/omap_hwmod.c @@ -1024,6 +1024,27 @@ static int __init _find_mpu_port_index(struct omap_hwmod *oh) return (found) ? i : -EINVAL; } +/** + * _find_mpu_rt_port - return omap_hwmod_ocp_if accessible by the MPU + * @oh: struct omap_hwmod * + * + * Given a pointer to a struct omap_hwmod record @oh, return a pointer + * to the struct omap_hwmod_ocp_if record that is used by the MPU to + * communicate with the IP block. This interface need not be directly + * connected to the MPU (and almost certainly is not), but is directly + * connected to the IP block represented by @oh. Returns a pointer + * to the struct omap_hwmod_ocp_if * upon success, or returns NULL upon + * error or if there does not appear to be a path from the MPU to this + * IP block. + */ +static struct omap_hwmod_ocp_if *_find_mpu_rt_port(struct omap_hwmod *oh) +{ + if (!oh || oh->_int_flags & _HWMOD_NO_MPU_PORT || oh->slaves_cnt == 0) + return NULL; + + return oh->slaves[oh->_mpu_port_index]; +}; + /** * _find_mpu_rt_addr_space - return MPU register target address space for @oh * @oh: struct omap_hwmod * @@ -1037,10 +1058,7 @@ static struct omap_hwmod_addr_space * __init _find_mpu_rt_addr_space(struct omap struct omap_hwmod_addr_space *mem; int found = 0, i = 0; - if (!oh || oh->_int_flags & _HWMOD_NO_MPU_PORT || oh->slaves_cnt == 0) - return NULL; - - os = oh->slaves[oh->_mpu_port_index]; + os = _find_mpu_rt_port(oh); if (!os->addr) return NULL; @@ -1298,12 +1316,11 @@ static int _wait_target_ready(struct omap_hwmod *oh) if (!oh) return -EINVAL; - if (oh->_int_flags & _HWMOD_NO_MPU_PORT) + if (oh->flags & HWMOD_NO_IDLEST) return 0; - os = oh->slaves[oh->_mpu_port_index]; - - if (oh->flags & HWMOD_NO_IDLEST) + os = _find_mpu_rt_port(oh); + if (!os) return 0; /* XXX check module SIDLEMODE */ @@ -2747,6 +2764,7 @@ int omap_hwmod_get_resource_byname(struct omap_hwmod *oh, unsigned int type, struct powerdomain *omap_hwmod_get_pwrdm(struct omap_hwmod *oh) { struct clk *c; + struct omap_hwmod_ocp_if *oi; if (!oh) return NULL; @@ -2754,9 +2772,10 @@ struct powerdomain *omap_hwmod_get_pwrdm(struct omap_hwmod *oh) if (oh->_clk) { c = oh->_clk; } else { - if (oh->_int_flags & _HWMOD_NO_MPU_PORT) + oi = _find_mpu_rt_port(oh); + if (!oi) return NULL; - c = oh->slaves[oh->_mpu_port_index]->_clk; + c = oi->_clk; } if (!c->clkdm) -- cgit v1.2.3 From 5d95dde7316101656102cb585b73381e4eaadaa7 Mon Sep 17 00:00:00 2001 From: Paul Walmsley Date: Thu, 19 Apr 2012 04:04:28 -0600 Subject: ARM: OMAP2+: hwmod: add function to iterate over struct omap_hwmod_ocp_if MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit To reduce the number of lines of data in the OMAP portion of the Linux code base, subsequent patches will remove the lists of hwmod interconnect links from the static hwmod data. These lists will be built dynamically during boot. To ease this transition, this patch centralizes the way that interconnect links are iterated into a single function, _fetch_next_ocp_if(). Signed-off-by: Paul Walmsley Cc: Benoît Cousson --- arch/arm/mach-omap2/omap_hwmod.c | 115 +++++++++++++++++++++++---------------- 1 file changed, 67 insertions(+), 48 deletions(-) (limited to 'arch/arm/mach-omap2/omap_hwmod.c') diff --git a/arch/arm/mach-omap2/omap_hwmod.c b/arch/arm/mach-omap2/omap_hwmod.c index 241c663a8f62..f74f3af95cae 100644 --- a/arch/arm/mach-omap2/omap_hwmod.c +++ b/arch/arm/mach-omap2/omap_hwmod.c @@ -168,6 +168,29 @@ static struct omap_hwmod *mpu_oh; /* Private functions */ +/** + * _fetch_next_ocp_if - return @i'th OCP interface in an array + * @p: ptr to a ptr to the list_head inside the ocp_if to return (not yet used) + * @old: ptr to an array of struct omap_hwmod_ocp_if records + * @i: pointer to the index into the @old array + * + * Return a pointer to the next struct omap_hwmod_ocp_if record in a + * sequence. Currently returns a struct omap_hwmod_ocp_if record + * corresponding to the element index pointed to by @i in the @old + * array, and increments the index pointed to by @i. + */ +static struct omap_hwmod_ocp_if *_fetch_next_ocp_if(struct list_head **p, + struct omap_hwmod_ocp_if **old, + int *i) +{ + struct omap_hwmod_ocp_if *oi; + + oi = old[*i]; + *i = *i + 1; + + return oi; +} + /** * _update_sysc_cache - return the module OCP_SYSCONFIG register, keep copy * @oh: struct omap_hwmod * @@ -582,16 +605,13 @@ static int _init_main_clk(struct omap_hwmod *oh) */ static int _init_interface_clks(struct omap_hwmod *oh) { + struct omap_hwmod_ocp_if *os; struct clk *c; - int i; + int i = 0; int ret = 0; - if (oh->slaves_cnt == 0) - return 0; - - for (i = 0; i < oh->slaves_cnt; i++) { - struct omap_hwmod_ocp_if *os = oh->slaves[i]; - + while (i < oh->slaves_cnt) { + os = _fetch_next_ocp_if(NULL, oh->slaves, &i); if (!os->clk) continue; @@ -643,21 +663,19 @@ static int _init_opt_clks(struct omap_hwmod *oh) */ static int _enable_clocks(struct omap_hwmod *oh) { - int i; + struct omap_hwmod_ocp_if *os; + int i = 0; pr_debug("omap_hwmod: %s: enabling clocks\n", oh->name); if (oh->_clk) clk_enable(oh->_clk); - if (oh->slaves_cnt > 0) { - for (i = 0; i < oh->slaves_cnt; i++) { - struct omap_hwmod_ocp_if *os = oh->slaves[i]; - struct clk *c = os->_clk; + while (i < oh->slaves_cnt) { + os = _fetch_next_ocp_if(NULL, oh->slaves, &i); - if (c && (os->flags & OCPIF_SWSUP_IDLE)) - clk_enable(c); - } + if (os->_clk && (os->flags & OCPIF_SWSUP_IDLE)) + clk_enable(os->_clk); } /* The opt clocks are controlled by the device driver. */ @@ -673,21 +691,19 @@ static int _enable_clocks(struct omap_hwmod *oh) */ static int _disable_clocks(struct omap_hwmod *oh) { - int i; + struct omap_hwmod_ocp_if *os; + int i = 0; pr_debug("omap_hwmod: %s: disabling clocks\n", oh->name); if (oh->_clk) clk_disable(oh->_clk); - if (oh->slaves_cnt > 0) { - for (i = 0; i < oh->slaves_cnt; i++) { - struct omap_hwmod_ocp_if *os = oh->slaves[i]; - struct clk *c = os->_clk; + while (i < oh->slaves_cnt) { + os = _fetch_next_ocp_if(NULL, oh->slaves, &i); - if (c && (os->flags & OCPIF_SWSUP_IDLE)) - clk_disable(c); - } + if (os->_clk && (os->flags & OCPIF_SWSUP_IDLE)) + clk_disable(os->_clk); } /* The opt clocks are controlled by the device driver. */ @@ -961,8 +977,9 @@ static int _get_addr_space_by_name(struct omap_hwmod *oh, const char *name, struct omap_hwmod_ocp_if *os; bool found = false; - for (i = 0; i < oh->slaves_cnt; i++) { - os = oh->slaves[i]; + i = 0; + while (i < oh->slaves_cnt) { + os = _fetch_next_ocp_if(NULL, oh->slaves, &i); if (!os->addr) return -ENOENT; @@ -999,15 +1016,15 @@ static int _get_addr_space_by_name(struct omap_hwmod *oh, const char *name, */ static int __init _find_mpu_port_index(struct omap_hwmod *oh) { - int i; + struct omap_hwmod_ocp_if *os; + int i = 0; int found = 0; - if (!oh || oh->slaves_cnt == 0) + if (!oh) return -EINVAL; - for (i = 0; i < oh->slaves_cnt; i++) { - struct omap_hwmod_ocp_if *os = oh->slaves[i]; - + while (i < oh->slaves_cnt) { + os = _fetch_next_ocp_if(NULL, oh->slaves, &i); if (os->user & OCP_USER_MPU) { found = 1; break; @@ -1016,12 +1033,12 @@ static int __init _find_mpu_port_index(struct omap_hwmod *oh) if (found) pr_debug("omap_hwmod: %s: MPU OCP slave port ID %d\n", - oh->name, i); + oh->name, i - 1); else pr_debug("omap_hwmod: %s: no MPU OCP slave port found\n", oh->name); - return (found) ? i : -EINVAL; + return (found) ? (i - 1) : -EINVAL; } /** @@ -2027,23 +2044,22 @@ static int __init _init(struct omap_hwmod *oh, void *data) */ static void __init _setup_iclk_autoidle(struct omap_hwmod *oh) { - int i; - + struct omap_hwmod_ocp_if *os; + int i = 0; if (oh->_state != _HWMOD_STATE_INITIALIZED) return; - for (i = 0; i < oh->slaves_cnt; i++) { - struct omap_hwmod_ocp_if *os = oh->slaves[i]; - struct clk *c = os->_clk; - if (!c) + while (i < oh->slaves_cnt) { + os = _fetch_next_ocp_if(NULL, oh->slaves, &i); + if (!os->_clk) continue; if (os->flags & OCPIF_SWSUP_IDLE) { /* XXX omap_iclk_deny_idle(c); */ } else { /* XXX omap_iclk_allow_idle(c); */ - clk_enable(c); + clk_enable(os->_clk); } } @@ -2623,12 +2639,16 @@ int omap_hwmod_reset(struct omap_hwmod *oh) */ int omap_hwmod_count_resources(struct omap_hwmod *oh) { - int ret, i; + struct omap_hwmod_ocp_if *os; + int ret; + int i = 0; ret = _count_mpu_irqs(oh) + _count_sdma_reqs(oh); - for (i = 0; i < oh->slaves_cnt; i++) - ret += _count_ocp_if_addr_spaces(oh->slaves[i]); + while (i < oh->slaves_cnt) { + os = _fetch_next_ocp_if(NULL, oh->slaves, &i); + ret += _count_ocp_if_addr_spaces(os); + } return ret; } @@ -2645,7 +2665,8 @@ int omap_hwmod_count_resources(struct omap_hwmod *oh) */ int omap_hwmod_fill_resources(struct omap_hwmod *oh, struct resource *res) { - int i, j, mpu_irqs_cnt, sdma_reqs_cnt; + struct omap_hwmod_ocp_if *os; + int i, j, mpu_irqs_cnt, sdma_reqs_cnt, addr_cnt; int r = 0; /* For each IRQ, DMA, memory area, fill in array.*/ @@ -2668,11 +2689,9 @@ int omap_hwmod_fill_resources(struct omap_hwmod *oh, struct resource *res) r++; } - for (i = 0; i < oh->slaves_cnt; i++) { - struct omap_hwmod_ocp_if *os; - int addr_cnt; - - os = oh->slaves[i]; + i = 0; + while (i < oh->slaves_cnt) { + os = _fetch_next_ocp_if(NULL, oh->slaves, &i); addr_cnt = _count_ocp_if_addr_spaces(os); for (j = 0; j < addr_cnt; j++) { -- cgit v1.2.3 From 24dbc2130179ebd493a241f6f5972cf6524b933a Mon Sep 17 00:00:00 2001 From: Paul Walmsley Date: Thu, 19 Apr 2012 04:04:29 -0600 Subject: ARM: OMAP2+: hwmod: consolidate finding the MPU port index and storing it MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit An IP block's MPU interface port only needs to be found once. The result can be cached to speed further lookups. This patch consolidates these two steps into a single function. Signed-off-by: Paul Walmsley Cc: Benoît Cousson --- arch/arm/mach-omap2/omap_hwmod.c | 39 +++++++++++++++------------------------ 1 file changed, 15 insertions(+), 24 deletions(-) (limited to 'arch/arm/mach-omap2/omap_hwmod.c') diff --git a/arch/arm/mach-omap2/omap_hwmod.c b/arch/arm/mach-omap2/omap_hwmod.c index f74f3af95cae..8cf837d2332a 100644 --- a/arch/arm/mach-omap2/omap_hwmod.c +++ b/arch/arm/mach-omap2/omap_hwmod.c @@ -1008,37 +1008,34 @@ static int _get_addr_space_by_name(struct omap_hwmod *oh, const char *name, } /** - * _find_mpu_port_index - find hwmod OCP slave port ID intended for MPU use + * _save_mpu_port_index - find and save the index to @oh's MPU port * @oh: struct omap_hwmod * * - * Returns the array index of the OCP slave port that the MPU - * addresses the device on, or -EINVAL upon error or not found. + * Determines the array index of the OCP slave port that the MPU uses + * to address the device, and saves it into the struct omap_hwmod. + * Intended to be called during hwmod registration only. No return + * value. */ -static int __init _find_mpu_port_index(struct omap_hwmod *oh) +static void __init _save_mpu_port_index(struct omap_hwmod *oh) { - struct omap_hwmod_ocp_if *os; + struct omap_hwmod_ocp_if *os = NULL; int i = 0; - int found = 0; if (!oh) - return -EINVAL; + return; + + oh->_int_flags |= _HWMOD_NO_MPU_PORT; while (i < oh->slaves_cnt) { os = _fetch_next_ocp_if(NULL, oh->slaves, &i); if (os->user & OCP_USER_MPU) { - found = 1; + oh->_mpu_port_index = i - 1; + oh->_int_flags &= ~_HWMOD_NO_MPU_PORT; break; } } - if (found) - pr_debug("omap_hwmod: %s: MPU OCP slave port ID %d\n", - oh->name, i - 1); - else - pr_debug("omap_hwmod: %s: no MPU OCP slave port found\n", - oh->name); - - return (found) ? (i - 1) : -EINVAL; + return; } /** @@ -1076,7 +1073,7 @@ static struct omap_hwmod_addr_space * __init _find_mpu_rt_addr_space(struct omap int found = 0, i = 0; os = _find_mpu_rt_port(oh); - if (!os->addr) + if (!os || !os->addr) return NULL; do { @@ -2213,8 +2210,6 @@ static int __init _setup(struct omap_hwmod *oh, void *data) */ static int __init _register(struct omap_hwmod *oh) { - int ms_id; - if (!oh || !oh->name || !oh->class || !oh->class->name || (oh->_state != _HWMOD_STATE_UNKNOWN)) return -EINVAL; @@ -2224,11 +2219,7 @@ static int __init _register(struct omap_hwmod *oh) if (_lookup(oh->name)) return -EEXIST; - ms_id = _find_mpu_port_index(oh); - if (!IS_ERR_VALUE(ms_id)) - oh->_mpu_port_index = ms_id; - else - oh->_int_flags |= _HWMOD_NO_MPU_PORT; + _save_mpu_port_index(oh); list_add_tail(&oh->node, &omap_hwmod_list); -- cgit v1.2.3 From 2221b5cddc2ebcfa4b0217266d2edc98e7eec93b Mon Sep 17 00:00:00 2001 From: Paul Walmsley Date: Thu, 19 Apr 2012 04:04:30 -0600 Subject: ARM: OMAP2+: hwmod: add support for link registration MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add support for direct IP block interconnect ("link") registration to the hwmod code via a new function, omap_hwmod_register_links(). This will replace direct registration of hwmods, and a subsequent patch will remove omap_hwmod_register(). This change will allow a subsequent patch to remove the hwmod data link arrays. This will reduce the size of the hwmod static data and also make it easier to generate the data files. It will also make it possible to share some of the struct omap_hwmod records across multiple SoCs, since the link array pointers will be removed from the struct omap_hwmod. The downside is that boot time will increase. Minimizing boot time was the reason why the link arrays were originally introduced. Removing them will require extra computation during boot to allocate memory and associate IP blocks with their interconnects. However, since the current kernel development focus is on reducing the number of lines in arch/arm/mach-omap2/, boot time impact is now seemingly considered a lower priority. This patch contains additional complexity to reduce the number of memory allocations required for this change. This reduces the boot time impact: total hwmod link registration time was ~ 2655 microseconds with a simple allocation strategy, but is now ~ 549 microseconds[1] with the approach taken by this patch. 1. Measured on a BeagleBoard 35xx @ 500MHz MPU/333 MHz CORE, average of 7 samples. Total uncertainty is +/- 61 microseconds. Signed-off-by: Paul Walmsley Cc: Benoît Cousson --- arch/arm/mach-omap2/omap_hwmod.c | 297 +++++++++++++++++++++++++-- arch/arm/plat-omap/include/plat/omap_hwmod.h | 24 +++ 2 files changed, 305 insertions(+), 16 deletions(-) (limited to 'arch/arm/mach-omap2/omap_hwmod.c') diff --git a/arch/arm/mach-omap2/omap_hwmod.c b/arch/arm/mach-omap2/omap_hwmod.c index 8cf837d2332a..99b913aa0cb9 100644 --- a/arch/arm/mach-omap2/omap_hwmod.c +++ b/arch/arm/mach-omap2/omap_hwmod.c @@ -137,6 +137,7 @@ #include #include #include +#include #include "common.h" #include @@ -159,25 +160,54 @@ /* Name of the OMAP hwmod for the MPU */ #define MPU_INITIATOR_NAME "mpu" +/* + * Number of struct omap_hwmod_link records per struct + * omap_hwmod_ocp_if record (master->slave and slave->master) + */ +#define LINKS_PER_OCP_IF 2 + /* omap_hwmod_list contains all registered struct omap_hwmods */ static LIST_HEAD(omap_hwmod_list); /* mpu_oh: used to add/remove MPU initiator from sleepdep list */ static struct omap_hwmod *mpu_oh; +/* + * link_registration: set to true if hwmod interfaces are being registered + * directly; set to false if hwmods are being registered directly + */ +static bool link_registration; + +/* + * linkspace: ptr to a buffer that struct omap_hwmod_link records are + * allocated from - used to reduce the number of small memory + * allocations, which has a significant impact on performance + */ +static struct omap_hwmod_link *linkspace; + +/* + * free_ls, max_ls: array indexes into linkspace; representing the + * next free struct omap_hwmod_link index, and the maximum number of + * struct omap_hwmod_link records allocated (respectively) + */ +static unsigned short free_ls, max_ls, ls_supp; /* Private functions */ /** - * _fetch_next_ocp_if - return @i'th OCP interface in an array - * @p: ptr to a ptr to the list_head inside the ocp_if to return (not yet used) + * _fetch_next_ocp_if - return next OCP interface in an array or list + * @p: ptr to a ptr to the list_head inside the ocp_if to return * @old: ptr to an array of struct omap_hwmod_ocp_if records * @i: pointer to the index into the @old array * * Return a pointer to the next struct omap_hwmod_ocp_if record in a - * sequence. Currently returns a struct omap_hwmod_ocp_if record - * corresponding to the element index pointed to by @i in the @old - * array, and increments the index pointed to by @i. + * sequence. If hwmods are being registered directly, then return a + * struct omap_hwmod_ocp_if record corresponding to the element index + * pointed to by @i in the + * @old array. Otherwise, return a pointer to the struct + * omap_hwmod_ocp_if record containing the struct list_head record pointed + * to by @p, and set the pointer pointed to by @p to point to the next + * struct list_head record in the list. */ static struct omap_hwmod_ocp_if *_fetch_next_ocp_if(struct list_head **p, struct omap_hwmod_ocp_if **old, @@ -185,7 +215,13 @@ static struct omap_hwmod_ocp_if *_fetch_next_ocp_if(struct list_head **p, { struct omap_hwmod_ocp_if *oi; - oi = old[*i]; + if (!link_registration) { + oi = old[*i]; + } else { + oi = list_entry(*p, struct omap_hwmod_link, node)->ocp_if; + *p = (*p)->next; + } + *i = *i + 1; return oi; @@ -606,12 +642,16 @@ static int _init_main_clk(struct omap_hwmod *oh) static int _init_interface_clks(struct omap_hwmod *oh) { struct omap_hwmod_ocp_if *os; + struct list_head *p = NULL; struct clk *c; int i = 0; int ret = 0; + if (link_registration) + p = oh->slave_ports.next; + while (i < oh->slaves_cnt) { - os = _fetch_next_ocp_if(NULL, oh->slaves, &i); + os = _fetch_next_ocp_if(&p, oh->slaves, &i); if (!os->clk) continue; @@ -664,6 +704,7 @@ static int _init_opt_clks(struct omap_hwmod *oh) static int _enable_clocks(struct omap_hwmod *oh) { struct omap_hwmod_ocp_if *os; + struct list_head *p = NULL; int i = 0; pr_debug("omap_hwmod: %s: enabling clocks\n", oh->name); @@ -671,8 +712,11 @@ static int _enable_clocks(struct omap_hwmod *oh) if (oh->_clk) clk_enable(oh->_clk); + if (link_registration) + p = oh->slave_ports.next; + while (i < oh->slaves_cnt) { - os = _fetch_next_ocp_if(NULL, oh->slaves, &i); + os = _fetch_next_ocp_if(&p, oh->slaves, &i); if (os->_clk && (os->flags & OCPIF_SWSUP_IDLE)) clk_enable(os->_clk); @@ -692,6 +736,7 @@ static int _enable_clocks(struct omap_hwmod *oh) static int _disable_clocks(struct omap_hwmod *oh) { struct omap_hwmod_ocp_if *os; + struct list_head *p = NULL; int i = 0; pr_debug("omap_hwmod: %s: disabling clocks\n", oh->name); @@ -699,8 +744,11 @@ static int _disable_clocks(struct omap_hwmod *oh) if (oh->_clk) clk_disable(oh->_clk); + if (link_registration) + p = oh->slave_ports.next; + while (i < oh->slaves_cnt) { - os = _fetch_next_ocp_if(NULL, oh->slaves, &i); + os = _fetch_next_ocp_if(&p, oh->slaves, &i); if (os->_clk && (os->flags & OCPIF_SWSUP_IDLE)) clk_disable(os->_clk); @@ -975,8 +1023,12 @@ static int _get_addr_space_by_name(struct omap_hwmod *oh, const char *name, { int i, j; struct omap_hwmod_ocp_if *os; + struct list_head *p = NULL; bool found = false; + if (link_registration) + p = oh->slave_ports.next; + i = 0; while (i < oh->slaves_cnt) { os = _fetch_next_ocp_if(NULL, oh->slaves, &i); @@ -1019,6 +1071,7 @@ static int _get_addr_space_by_name(struct omap_hwmod *oh, const char *name, static void __init _save_mpu_port_index(struct omap_hwmod *oh) { struct omap_hwmod_ocp_if *os = NULL; + struct list_head *p = NULL; int i = 0; if (!oh) @@ -1026,9 +1079,13 @@ static void __init _save_mpu_port_index(struct omap_hwmod *oh) oh->_int_flags |= _HWMOD_NO_MPU_PORT; + if (link_registration) + p = oh->slave_ports.next; + while (i < oh->slaves_cnt) { - os = _fetch_next_ocp_if(NULL, oh->slaves, &i); + os = _fetch_next_ocp_if(&p, oh->slaves, &i); if (os->user & OCP_USER_MPU) { + oh->_mpu_port = os; oh->_mpu_port_index = i - 1; oh->_int_flags &= ~_HWMOD_NO_MPU_PORT; break; @@ -1056,7 +1113,10 @@ static struct omap_hwmod_ocp_if *_find_mpu_rt_port(struct omap_hwmod *oh) if (!oh || oh->_int_flags & _HWMOD_NO_MPU_PORT || oh->slaves_cnt == 0) return NULL; - return oh->slaves[oh->_mpu_port_index]; + if (!link_registration) + return oh->slaves[oh->_mpu_port_index]; + else + return oh->_mpu_port; }; /** @@ -1976,6 +2036,8 @@ static void __init _init_mpu_rt_base(struct omap_hwmod *oh, void *data) if (!oh) return; + _save_mpu_port_index(oh); + if (oh->_int_flags & _HWMOD_NO_MPU_PORT) return; @@ -2042,13 +2104,16 @@ static int __init _init(struct omap_hwmod *oh, void *data) static void __init _setup_iclk_autoidle(struct omap_hwmod *oh) { struct omap_hwmod_ocp_if *os; + struct list_head *p = NULL; int i = 0; if (oh->_state != _HWMOD_STATE_INITIALIZED) return; + if (link_registration) + p = oh->slave_ports.next; while (i < oh->slaves_cnt) { - os = _fetch_next_ocp_if(NULL, oh->slaves, &i); + os = _fetch_next_ocp_if(&p, oh->slaves, &i); if (!os->_clk) continue; @@ -2219,10 +2284,10 @@ static int __init _register(struct omap_hwmod *oh) if (_lookup(oh->name)) return -EEXIST; - _save_mpu_port_index(oh); - list_add_tail(&oh->node, &omap_hwmod_list); + INIT_LIST_HEAD(&oh->master_ports); + INIT_LIST_HEAD(&oh->slave_ports); spin_lock_init(&oh->_lock); oh->_state = _HWMOD_STATE_REGISTERED; @@ -2237,6 +2302,160 @@ static int __init _register(struct omap_hwmod *oh) return 0; } +/** + * _alloc_links - return allocated memory for hwmod links + * @ml: pointer to a struct omap_hwmod_link * for the master link + * @sl: pointer to a struct omap_hwmod_link * for the slave link + * + * Return pointers to two struct omap_hwmod_link records, via the + * addresses pointed to by @ml and @sl. Will first attempt to return + * memory allocated as part of a large initial block, but if that has + * been exhausted, will allocate memory itself. Since ideally this + * second allocation path will never occur, the number of these + * 'supplemental' allocations will be logged when debugging is + * enabled. Returns 0. + */ +static int __init _alloc_links(struct omap_hwmod_link **ml, + struct omap_hwmod_link **sl) +{ + unsigned int sz; + + if ((free_ls + LINKS_PER_OCP_IF) <= max_ls) { + *ml = &linkspace[free_ls++]; + *sl = &linkspace[free_ls++]; + return 0; + } + + sz = sizeof(struct omap_hwmod_link) * LINKS_PER_OCP_IF; + + *sl = NULL; + *ml = alloc_bootmem(sz); + + memset(*ml, 0, sz); + + *sl = (void *)(*ml) + sizeof(struct omap_hwmod_link); + + ls_supp++; + pr_debug("omap_hwmod: supplemental link allocations needed: %d\n", + ls_supp * LINKS_PER_OCP_IF); + + return 0; +}; + +/** + * _add_link - add an interconnect between two IP blocks + * @oi: pointer to a struct omap_hwmod_ocp_if record + * + * Add struct omap_hwmod_link records connecting the master IP block + * specified in @oi->master to @oi, and connecting the slave IP block + * specified in @oi->slave to @oi. This code is assumed to run before + * preemption or SMP has been enabled, thus avoiding the need for + * 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) +{ + struct omap_hwmod_link *ml, *sl; + + pr_debug("omap_hwmod: %s -> %s: adding link\n", oi->master->name, + oi->slave->name); + + _alloc_links(&ml, &sl); + + ml->ocp_if = oi; + INIT_LIST_HEAD(&ml->node); + list_add(&ml->node, &oi->master->master_ports); + oi->master->masters_cnt++; + + sl->ocp_if = oi; + INIT_LIST_HEAD(&sl->node); + list_add(&sl->node, &oi->slave->slave_ports); + oi->slave->slaves_cnt++; + + return 0; +} + +/** + * _register_link - register a struct omap_hwmod_ocp_if + * @oi: struct omap_hwmod_ocp_if * + * + * Registers the omap_hwmod_ocp_if record @oi. Returns -EEXIST if it + * has already been registered; -EINVAL if @oi is NULL or if the + * record pointed to by @oi is missing required fields; or 0 upon + * success. + * + * XXX The data should be copied into bootmem, so the original data + * should be marked __initdata and freed after init. This would allow + * unneeded omap_hwmods to be freed on multi-OMAP configurations. + */ +static int __init _register_link(struct omap_hwmod_ocp_if *oi) +{ + if (!oi || !oi->master || !oi->slave || !oi->user) + return -EINVAL; + + if (oi->_int_flags & _OCPIF_INT_FLAGS_REGISTERED) + return -EEXIST; + + pr_debug("omap_hwmod: registering link from %s to %s\n", + oi->master->name, oi->slave->name); + + /* + * Register the connected hwmods, if they haven't been + * registered already + */ + if (oi->master->_state != _HWMOD_STATE_REGISTERED) + _register(oi->master); + + if (oi->slave->_state != _HWMOD_STATE_REGISTERED) + _register(oi->slave); + + _add_link(oi); + + oi->_int_flags |= _OCPIF_INT_FLAGS_REGISTERED; + + return 0; +} + +/** + * _alloc_linkspace - allocate large block of hwmod links + * @ois: pointer to an array of struct omap_hwmod_ocp_if records to count + * + * Allocate a large block of struct omap_hwmod_link records. This + * improves boot time significantly by avoiding the need to allocate + * individual records one by one. If the number of records to + * allocate in the block hasn't been manually specified, this function + * will count the number of struct omap_hwmod_ocp_if records in @ois + * and use that to determine the allocation size. For SoC families + * that require multiple list registrations, such as OMAP3xxx, this + * estimation process isn't optimal, so manual estimation is advised + * in those cases. Returns -EEXIST if the allocation has already occurred + * or 0 upon success. + */ +static int __init _alloc_linkspace(struct omap_hwmod_ocp_if **ois) +{ + unsigned int i = 0; + unsigned int sz; + + if (linkspace) { + WARN(1, "linkspace already allocated\n"); + return -EEXIST; + } + + if (max_ls == 0) + while (ois[i++]) + max_ls += LINKS_PER_OCP_IF; + + sz = sizeof(struct omap_hwmod_link) * max_ls; + + pr_debug("omap_hwmod: %s: allocating %d byte linkspace (%d links)\n", + __func__, sz, max_ls); + + linkspace = alloc_bootmem(sz); + + memset(linkspace, 0, sz); + + return 0; +} /* Public functions */ @@ -2376,6 +2595,9 @@ int __init omap_hwmod_register(struct omap_hwmod **ohs) { int r, i; + if (link_registration) + return -EINVAL; + if (!ohs) return 0; @@ -2389,6 +2611,41 @@ int __init omap_hwmod_register(struct omap_hwmod **ohs) return 0; } +/** + * omap_hwmod_register_links - register an array of hwmod links + * @ois: pointer to an array of omap_hwmod_ocp_if to register + * + * Intended to be called early in boot before the clock framework is + * initialized. If @ois is not null, will register all omap_hwmods + * listed in @ois that are valid for this chip. Returns 0. + */ +int __init omap_hwmod_register_links(struct omap_hwmod_ocp_if **ois) +{ + int r, i; + + if (!ois) + return 0; + + link_registration = true; + + if (!linkspace) { + if (_alloc_linkspace(ois)) { + pr_err("omap_hwmod: could not allocate link space\n"); + return -ENOMEM; + } + } + + i = 0; + do { + r = _register_link(ois[i]); + WARN(r && r != -EEXIST, + "omap_hwmod: _register_link(%s -> %s) returned %d\n", + ois[i]->master->name, ois[i]->slave->name, r); + } while (ois[++i]); + + return 0; +} + /** * _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) @@ -2631,13 +2888,17 @@ int omap_hwmod_reset(struct omap_hwmod *oh) int omap_hwmod_count_resources(struct omap_hwmod *oh) { struct omap_hwmod_ocp_if *os; + struct list_head *p = NULL; int ret; int i = 0; ret = _count_mpu_irqs(oh) + _count_sdma_reqs(oh); + if (link_registration) + p = oh->slave_ports.next; + while (i < oh->slaves_cnt) { - os = _fetch_next_ocp_if(NULL, oh->slaves, &i); + os = _fetch_next_ocp_if(&p, oh->slaves, &i); ret += _count_ocp_if_addr_spaces(os); } @@ -2657,6 +2918,7 @@ int omap_hwmod_count_resources(struct omap_hwmod *oh) int omap_hwmod_fill_resources(struct omap_hwmod *oh, struct resource *res) { struct omap_hwmod_ocp_if *os; + struct list_head *p = NULL; int i, j, mpu_irqs_cnt, sdma_reqs_cnt, addr_cnt; int r = 0; @@ -2680,9 +2942,12 @@ int omap_hwmod_fill_resources(struct omap_hwmod *oh, struct resource *res) r++; } + if (link_registration) + p = oh->slave_ports.next; + i = 0; while (i < oh->slaves_cnt) { - os = _fetch_next_ocp_if(NULL, oh->slaves, &i); + os = _fetch_next_ocp_if(&p, oh->slaves, &i); addr_cnt = _count_ocp_if_addr_spaces(os); for (j = 0; j < addr_cnt; j++) { diff --git a/arch/arm/plat-omap/include/plat/omap_hwmod.h b/arch/arm/plat-omap/include/plat/omap_hwmod.h index 65285317f80b..09679032603c 100644 --- a/arch/arm/plat-omap/include/plat/omap_hwmod.h +++ b/arch/arm/plat-omap/include/plat/omap_hwmod.h @@ -219,6 +219,10 @@ struct omap_hwmod_addr_space { #define OCPIF_SWSUP_IDLE (1 << 0) #define OCPIF_CAN_BURST (1 << 1) +/* omap_hwmod_ocp_if._int_flags possibilities */ +#define _OCPIF_INT_FLAGS_REGISTERED (1 << 0) + + /** * struct omap_hwmod_ocp_if - OCP interface data * @master: struct omap_hwmod that initiates OCP transactions on this link @@ -230,6 +234,7 @@ struct omap_hwmod_addr_space { * @width: OCP data width * @user: initiators using this interface (see OCP_USER_* macros above) * @flags: OCP interface flags (see OCPIF_* macros above) + * @_int_flags: internal flags (see _OCPIF_INT_FLAGS* macros above) * * It may also be useful to add a tag_cnt field for OCP2.x devices. * @@ -248,6 +253,7 @@ struct omap_hwmod_ocp_if { u8 width; u8 user; u8 flags; + u8 _int_flags; }; @@ -476,6 +482,16 @@ struct omap_hwmod_class { int (*reset)(struct omap_hwmod *oh); }; +/** + * struct omap_hwmod_link - internal structure linking hwmods with ocp_ifs + * @ocp_if: OCP interface structure record pointer + * @node: list_head pointing to next struct omap_hwmod_link in a list + */ +struct omap_hwmod_link { + struct omap_hwmod_ocp_if *ocp_if; + struct list_head node; +}; + /** * struct omap_hwmod - integration data for OMAP hardware "modules" (IP blocks) * @name: name of the hwmod @@ -494,6 +510,7 @@ struct omap_hwmod_class { * @_sysc_cache: internal-use hwmod flags * @_mpu_rt_va: cached register target start address (internal use) * @_mpu_port_index: cached MPU register target slave ID (internal use) + * @_mpu_port: cached MPU register target slave (internal use) * @opt_clks_cnt: number of @opt_clks * @master_cnt: number of @master entries * @slaves_cnt: number of @slave entries @@ -512,6 +529,8 @@ struct omap_hwmod_class { * * Parameter names beginning with an underscore are managed internally by * the omap_hwmod code and should not be set during initialization. + * + * @masters and @slaves are now deprecated. */ struct omap_hwmod { const char *name; @@ -532,11 +551,14 @@ struct omap_hwmod { struct clockdomain *clkdm; struct omap_hwmod_ocp_if **masters; /* connect to *_IA */ struct omap_hwmod_ocp_if **slaves; /* connect to *_TA */ + struct list_head master_ports; /* connect to *_IA */ + struct list_head slave_ports; /* connect to *_TA */ void *dev_attr; u32 _sysc_cache; void __iomem *_mpu_rt_va; spinlock_t _lock; struct list_head node; + struct omap_hwmod_ocp_if *_mpu_port; u16 flags; u8 _mpu_port_index; u8 response_lat; @@ -622,4 +644,6 @@ extern int omap2430_hwmod_init(void); extern int omap3xxx_hwmod_init(void); extern int omap44xx_hwmod_init(void); +extern int __init omap_hwmod_register_links(struct omap_hwmod_ocp_if **ois); + #endif -- cgit v1.2.3 From 11cd4b94cb491894b8a192635abf159fc1917f4d Mon Sep 17 00:00:00 2001 From: Paul Walmsley Date: Thu, 19 Apr 2012 04:04:32 -0600 Subject: ARM: OMAP: hwmod: remove code support for direct hwmod registration MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Now that the data has been converted to use interface registration, we can remove the (now unused) direct hwmod registration code. Signed-off-by: Paul Walmsley Cc: Benoît Cousson --- arch/arm/mach-omap2/omap_hwmod.c | 124 +++++++-------------------- arch/arm/plat-omap/include/plat/omap_hwmod.h | 7 -- 2 files changed, 33 insertions(+), 98 deletions(-) (limited to 'arch/arm/mach-omap2/omap_hwmod.c') diff --git a/arch/arm/mach-omap2/omap_hwmod.c b/arch/arm/mach-omap2/omap_hwmod.c index 99b913aa0cb9..bf86f7e8f91f 100644 --- a/arch/arm/mach-omap2/omap_hwmod.c +++ b/arch/arm/mach-omap2/omap_hwmod.c @@ -172,12 +172,6 @@ static LIST_HEAD(omap_hwmod_list); /* mpu_oh: used to add/remove MPU initiator from sleepdep list */ static struct omap_hwmod *mpu_oh; -/* - * link_registration: set to true if hwmod interfaces are being registered - * directly; set to false if hwmods are being registered directly - */ -static bool link_registration; - /* * linkspace: ptr to a buffer that struct omap_hwmod_link records are * allocated from - used to reduce the number of small memory @@ -195,32 +189,22 @@ static unsigned short free_ls, max_ls, ls_supp; /* Private functions */ /** - * _fetch_next_ocp_if - return next OCP interface in an array or list + * _fetch_next_ocp_if - return the next OCP interface in a list * @p: ptr to a ptr to the list_head inside the ocp_if to return - * @old: ptr to an array of struct omap_hwmod_ocp_if records - * @i: pointer to the index into the @old array - * - * Return a pointer to the next struct omap_hwmod_ocp_if record in a - * sequence. If hwmods are being registered directly, then return a - * struct omap_hwmod_ocp_if record corresponding to the element index - * pointed to by @i in the - * @old array. Otherwise, return a pointer to the struct - * omap_hwmod_ocp_if record containing the struct list_head record pointed - * to by @p, and set the pointer pointed to by @p to point to the next - * struct list_head record in the list. + * @i: pointer to the index of the element pointed to by @p in the list + * + * Return a pointer to the struct omap_hwmod_ocp_if record + * containing the struct list_head pointed to by @p, and increment + * @p such that a future call to this routine will return the next + * record. */ static struct omap_hwmod_ocp_if *_fetch_next_ocp_if(struct list_head **p, - struct omap_hwmod_ocp_if **old, int *i) { struct omap_hwmod_ocp_if *oi; - if (!link_registration) { - oi = old[*i]; - } else { - oi = list_entry(*p, struct omap_hwmod_link, node)->ocp_if; - *p = (*p)->next; - } + oi = list_entry(*p, struct omap_hwmod_link, node)->ocp_if; + *p = (*p)->next; *i = *i + 1; @@ -642,16 +626,15 @@ static int _init_main_clk(struct omap_hwmod *oh) static int _init_interface_clks(struct omap_hwmod *oh) { struct omap_hwmod_ocp_if *os; - struct list_head *p = NULL; + struct list_head *p; struct clk *c; int i = 0; int ret = 0; - if (link_registration) - p = oh->slave_ports.next; + p = oh->slave_ports.next; while (i < oh->slaves_cnt) { - os = _fetch_next_ocp_if(&p, oh->slaves, &i); + os = _fetch_next_ocp_if(&p, &i); if (!os->clk) continue; @@ -704,7 +687,7 @@ static int _init_opt_clks(struct omap_hwmod *oh) static int _enable_clocks(struct omap_hwmod *oh) { struct omap_hwmod_ocp_if *os; - struct list_head *p = NULL; + struct list_head *p; int i = 0; pr_debug("omap_hwmod: %s: enabling clocks\n", oh->name); @@ -712,11 +695,10 @@ static int _enable_clocks(struct omap_hwmod *oh) if (oh->_clk) clk_enable(oh->_clk); - if (link_registration) - p = oh->slave_ports.next; + p = oh->slave_ports.next; while (i < oh->slaves_cnt) { - os = _fetch_next_ocp_if(&p, oh->slaves, &i); + os = _fetch_next_ocp_if(&p, &i); if (os->_clk && (os->flags & OCPIF_SWSUP_IDLE)) clk_enable(os->_clk); @@ -736,7 +718,7 @@ static int _enable_clocks(struct omap_hwmod *oh) static int _disable_clocks(struct omap_hwmod *oh) { struct omap_hwmod_ocp_if *os; - struct list_head *p = NULL; + struct list_head *p; int i = 0; pr_debug("omap_hwmod: %s: disabling clocks\n", oh->name); @@ -744,11 +726,10 @@ static int _disable_clocks(struct omap_hwmod *oh) if (oh->_clk) clk_disable(oh->_clk); - if (link_registration) - p = oh->slave_ports.next; + p = oh->slave_ports.next; while (i < oh->slaves_cnt) { - os = _fetch_next_ocp_if(&p, oh->slaves, &i); + os = _fetch_next_ocp_if(&p, &i); if (os->_clk && (os->flags & OCPIF_SWSUP_IDLE)) clk_disable(os->_clk); @@ -1026,12 +1007,11 @@ static int _get_addr_space_by_name(struct omap_hwmod *oh, const char *name, struct list_head *p = NULL; bool found = false; - if (link_registration) - p = oh->slave_ports.next; + p = oh->slave_ports.next; i = 0; while (i < oh->slaves_cnt) { - os = _fetch_next_ocp_if(NULL, oh->slaves, &i); + os = _fetch_next_ocp_if(&p, &i); if (!os->addr) return -ENOENT; @@ -1071,7 +1051,7 @@ static int _get_addr_space_by_name(struct omap_hwmod *oh, const char *name, static void __init _save_mpu_port_index(struct omap_hwmod *oh) { struct omap_hwmod_ocp_if *os = NULL; - struct list_head *p = NULL; + struct list_head *p; int i = 0; if (!oh) @@ -1079,14 +1059,12 @@ static void __init _save_mpu_port_index(struct omap_hwmod *oh) oh->_int_flags |= _HWMOD_NO_MPU_PORT; - if (link_registration) - p = oh->slave_ports.next; + p = oh->slave_ports.next; while (i < oh->slaves_cnt) { - os = _fetch_next_ocp_if(&p, oh->slaves, &i); + os = _fetch_next_ocp_if(&p, &i); if (os->user & OCP_USER_MPU) { oh->_mpu_port = os; - oh->_mpu_port_index = i - 1; oh->_int_flags &= ~_HWMOD_NO_MPU_PORT; break; } @@ -1113,10 +1091,7 @@ static struct omap_hwmod_ocp_if *_find_mpu_rt_port(struct omap_hwmod *oh) if (!oh || oh->_int_flags & _HWMOD_NO_MPU_PORT || oh->slaves_cnt == 0) return NULL; - if (!link_registration) - return oh->slaves[oh->_mpu_port_index]; - else - return oh->_mpu_port; + return oh->_mpu_port; }; /** @@ -2104,16 +2079,15 @@ static int __init _init(struct omap_hwmod *oh, void *data) static void __init _setup_iclk_autoidle(struct omap_hwmod *oh) { struct omap_hwmod_ocp_if *os; - struct list_head *p = NULL; + struct list_head *p; int i = 0; if (oh->_state != _HWMOD_STATE_INITIALIZED) return; - if (link_registration) - p = oh->slave_ports.next; + p = oh->slave_ports.next; while (i < oh->slaves_cnt) { - os = _fetch_next_ocp_if(&p, oh->slaves, &i); + os = _fetch_next_ocp_if(&p, &i); if (!os->_clk) continue; @@ -2583,34 +2557,6 @@ int omap_hwmod_for_each(int (*fn)(struct omap_hwmod *oh, void *data), return ret; } -/** - * omap_hwmod_register - register an array of hwmods - * @ohs: pointer to an array of omap_hwmods to register - * - * Intended to be called early in boot before the clock framework is - * initialized. If @ohs is not null, will register all omap_hwmods - * listed in @ohs that are valid for this chip. Returns 0. - */ -int __init omap_hwmod_register(struct omap_hwmod **ohs) -{ - int r, i; - - if (link_registration) - return -EINVAL; - - if (!ohs) - return 0; - - i = 0; - do { - r = _register(ohs[i]); - WARN(r, "omap_hwmod: %s: _register returned %d\n", ohs[i]->name, - r); - } while (ohs[++i]); - - return 0; -} - /** * omap_hwmod_register_links - register an array of hwmod links * @ois: pointer to an array of omap_hwmod_ocp_if to register @@ -2626,8 +2572,6 @@ int __init omap_hwmod_register_links(struct omap_hwmod_ocp_if **ois) if (!ois) return 0; - link_registration = true; - if (!linkspace) { if (_alloc_linkspace(ois)) { pr_err("omap_hwmod: could not allocate link space\n"); @@ -2888,17 +2832,16 @@ int omap_hwmod_reset(struct omap_hwmod *oh) int omap_hwmod_count_resources(struct omap_hwmod *oh) { struct omap_hwmod_ocp_if *os; - struct list_head *p = NULL; + struct list_head *p; int ret; int i = 0; ret = _count_mpu_irqs(oh) + _count_sdma_reqs(oh); - if (link_registration) - p = oh->slave_ports.next; + p = oh->slave_ports.next; while (i < oh->slaves_cnt) { - os = _fetch_next_ocp_if(&p, oh->slaves, &i); + os = _fetch_next_ocp_if(&p, &i); ret += _count_ocp_if_addr_spaces(os); } @@ -2918,7 +2861,7 @@ int omap_hwmod_count_resources(struct omap_hwmod *oh) int omap_hwmod_fill_resources(struct omap_hwmod *oh, struct resource *res) { struct omap_hwmod_ocp_if *os; - struct list_head *p = NULL; + struct list_head *p; int i, j, mpu_irqs_cnt, sdma_reqs_cnt, addr_cnt; int r = 0; @@ -2942,12 +2885,11 @@ int omap_hwmod_fill_resources(struct omap_hwmod *oh, struct resource *res) r++; } - if (link_registration) - p = oh->slave_ports.next; + p = oh->slave_ports.next; i = 0; while (i < oh->slaves_cnt) { - os = _fetch_next_ocp_if(&p, oh->slaves, &i); + os = _fetch_next_ocp_if(&p, &i); addr_cnt = _count_ocp_if_addr_spaces(os); for (j = 0; j < addr_cnt; j++) { diff --git a/arch/arm/plat-omap/include/plat/omap_hwmod.h b/arch/arm/plat-omap/include/plat/omap_hwmod.h index 09679032603c..14dde32cd406 100644 --- a/arch/arm/plat-omap/include/plat/omap_hwmod.h +++ b/arch/arm/plat-omap/include/plat/omap_hwmod.h @@ -504,12 +504,9 @@ struct omap_hwmod_link { * @_clk: pointer to the main struct clk (filled in at runtime) * @opt_clks: other device clocks that drivers can request (0..*) * @voltdm: pointer to voltage domain (filled in at runtime) - * @masters: ptr to array of OCP ifs that this hwmod can initiate on - * @slaves: ptr to array of OCP ifs that this hwmod can respond on * @dev_attr: arbitrary device attributes that can be passed to the driver * @_sysc_cache: internal-use hwmod flags * @_mpu_rt_va: cached register target start address (internal use) - * @_mpu_port_index: cached MPU register target slave ID (internal use) * @_mpu_port: cached MPU register target slave (internal use) * @opt_clks_cnt: number of @opt_clks * @master_cnt: number of @master entries @@ -549,8 +546,6 @@ struct omap_hwmod { struct omap_hwmod_opt_clk *opt_clks; char *clkdm_name; struct clockdomain *clkdm; - struct omap_hwmod_ocp_if **masters; /* connect to *_IA */ - struct omap_hwmod_ocp_if **slaves; /* connect to *_TA */ struct list_head master_ports; /* connect to *_IA */ struct list_head slave_ports; /* connect to *_TA */ void *dev_attr; @@ -560,7 +555,6 @@ struct omap_hwmod { struct list_head node; struct omap_hwmod_ocp_if *_mpu_port; u16 flags; - u8 _mpu_port_index; u8 response_lat; u8 rst_lines_cnt; u8 opt_clks_cnt; @@ -572,7 +566,6 @@ struct omap_hwmod { u8 _postsetup_state; }; -int omap_hwmod_register(struct omap_hwmod **ohs); struct omap_hwmod *omap_hwmod_lookup(const char *name); int omap_hwmod_for_each(int (*fn)(struct omap_hwmod *oh, void *data), void *data); -- cgit v1.2.3