From patchwork Thu Oct 14 18:37:34 2010 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Paul Walmsley X-Patchwork-Id: 253931 X-Patchwork-Delegate: paul@pwsan.com Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by demeter1.kernel.org (8.14.4/8.14.3) with ESMTP id o9EIbban007561 for ; Thu, 14 Oct 2010 18:37:37 GMT Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1755797Ab0JNShg (ORCPT ); Thu, 14 Oct 2010 14:37:36 -0400 Received: from utopia.booyaka.com ([72.9.107.138]:46105 "EHLO utopia.booyaka.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1755913Ab0JNShf (ORCPT ); Thu, 14 Oct 2010 14:37:35 -0400 Received: (qmail 17834 invoked by uid 1019); 14 Oct 2010 18:37:34 -0000 Date: Thu, 14 Oct 2010 12:37:34 -0600 (MDT) From: Paul Walmsley To: "Varadarajan, Charulatha" cc: Kevin Hilman , "Cousson, Benoit" , "linux-omap@vger.kernel.org" Subject: RE: [PATCH] omap2plus: wdt: Fix boot warn when CONFIG_PM_RUNTIME=n In-Reply-To: Message-ID: References: <1286798556-22749-1-git-send-email-charu@ti.com> <4CB40B07.8080301@ti.com> <4CB45E0E.6080104@ti.com> <87mxqj1d2v.fsf@deeprootsystems.com> User-Agent: Alpine 2.00 (DEB 1167 2008-08-23) MIME-Version: 1.0 Sender: linux-omap-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-omap@vger.kernel.org X-Greylist: IP, sender and recipient auto-whitelisted, not delayed by milter-greylist-4.2.3 (demeter1.kernel.org [140.211.167.41]); Thu, 14 Oct 2010 18:37:37 +0000 (UTC) diff --git a/arch/arm/mach-omap2/io.c b/arch/arm/mach-omap2/io.c index 40562dd..e3a423d 100644 --- a/arch/arm/mach-omap2/io.c +++ b/arch/arm/mach-omap2/io.c @@ -311,10 +311,15 @@ static int __init _omap2_init_reprogram_sdrc(void) return v; } -void __init omap2_init_common_hw(struct omap_sdrc_params *sdrc_cs0, - struct omap_sdrc_params *sdrc_cs1) +/* XXX document */ +static int _set_hwmod_postsetup_state(struct omap_hwmod *oh, void *data) +{ + return omap_hwmod_set_postsetup_state(oh, *(u8 *)data); +} + +static void __init omap2_init_common_infra(void) { - u8 skip_setup_idle = 0; + u8 postsetup_state; pwrdm_init(powerdomains_omap); clkdm_init(clockdomains_omap, clkdm_autodeps); @@ -327,6 +332,24 @@ void __init omap2_init_common_hw(struct omap_sdrc_params *sdrc_cs0, else if (cpu_is_omap44xx()) omap44xx_hwmod_init(); + /* Set the default postsetup state for all hwmods ... */ +#ifdef CONFIG_PM_RUNTIME + postsetup_state = _HWMOD_STATE_IDLE; +#else + postsetup_state = _HWMOD_STATE_ENABLED; +#endif + omap_hwmod_for_each(_set_hwmod_postsetup_state, &postsetup_state); + + /* ... then handle the exceptions for unusual modules (like MPU WDT) */ + /* + * XXX ideally we could detect whether the MPU WDT was currently + * enabled here and make this conditional + */ + postsetup_state = _HWMOD_STATE_DISABLED; + omap_hwmod_for_each_by_class("wd_timer_enabled_on_reset", + _set_hwmod_postsetup_state, + &postsetup_state); + /* The OPP tables have to be registered before a clk init */ omap_pm_if_early_init(mpu_opps, dsp_opps, l3_opps); @@ -340,16 +363,32 @@ void __init omap2_init_common_hw(struct omap_sdrc_params *sdrc_cs0, omap4xxx_clk_init(); else pr_err("Could not init clock framework - unknown CPU\n"); +} +static void __init omap2_init_common_devices(struct omap_sdrc_params *sdrc_cs0, + struct omap_sdrc_params *sdrc_cs1) +{ omap_serial_early_init(); -#ifndef CONFIG_PM_RUNTIME - skip_setup_idle = 1; -#endif - omap_hwmod_late_init(skip_setup_idle); + omap_hwmod_late_init(); + if (cpu_is_omap24xx() || cpu_is_omap34xx()) { omap2_sdrc_init(sdrc_cs0, sdrc_cs1); _omap2_init_reprogram_sdrc(); } gpmc_init(); } + +/* + * XXX this function should go away and the board-*.c files should call + * both omap2_init_common_infra() and omap2_init_common_devices(), + * so the board-*.c files can override some default hwmod postsetup_states + * (e.g., for watchdog) between the two functions. + */ +void __init omap2_init_common_hw(struct omap_sdrc_params *sdrc_cs0, + struct omap_sdrc_params *sdrc_cs1) +{ + omap2_init_common_infra(); + omap2_init_common_devices(sdrc_cs0, sdrc_cs1); +} + diff --git a/arch/arm/mach-omap2/omap_hwmod.c b/arch/arm/mach-omap2/omap_hwmod.c index 5a30658..618e135 100644 --- a/arch/arm/mach-omap2/omap_hwmod.c +++ b/arch/arm/mach-omap2/omap_hwmod.c @@ -1298,24 +1298,19 @@ static int _shutdown(struct omap_hwmod *oh) /** * _setup - do initial configuration of omap_hwmod * @oh: struct omap_hwmod * - * @skip_setup_idle_p: do not idle hwmods at the end of the fn if 1 * * Writes the CLOCKACTIVITY bits @clockact to the hwmod @oh - * OCP_SYSCONFIG register. @skip_setup_idle is intended to be used on - * a system that will not call omap_hwmod_enable() to enable devices - * (e.g., a system without PM runtime). Returns -EINVAL if the hwmod - * is in the wrong state or returns 0. + * OCP_SYSCONFIG register. Returns -EINVAL if the hwmod is in the + * wrong state or returns 0. */ static int _setup(struct omap_hwmod *oh, void *data) { int i, r; - u8 skip_setup_idle; + u8 postsetup_state; if (!oh || !data) return -EINVAL; - skip_setup_idle = *(u8 *)data; - /* Set iclk autoidle mode */ if (oh->slaves_cnt > 0) { for (i = 0; i < oh->slaves_cnt; i++) { @@ -1368,8 +1363,24 @@ static int _setup(struct omap_hwmod *oh, void *data) } } - if (!(oh->flags & HWMOD_INIT_NO_IDLE) && !skip_setup_idle) + postsetup_state = oh->_postsetup_state; + if (postsetup_state == _HWMOD_STATE_UNKNOWN) + postsetup_state = _HWMOD_STATE_ENABLED; + + /* + * XXX HWMOD_INIT_NO_IDLE does not belong in hwmod data - + * it should be set by the core code as a runtime flag during startup + */ + if (!(oh->flags & HWMOD_INIT_NO_IDLE)) + postsetup_state = _HWMOD_STATE_IDLE; + + if (postsetup_state == _HWMOD_STATE_IDLE) _omap_hwmod_idle(oh); + else if (postsetup_state == _HWMOD_STATE_DISABLED) + _shutdown(oh); + else + WARN(1, "hwmod: %s: unknown postsetup state %d! defaulting to enabled\n", + oh->name, postsetup_state); return 0; } @@ -1570,13 +1581,12 @@ int omap_hwmod_init(struct omap_hwmod **ohs) /** * omap_hwmod_late_init - do some post-clock framework initialization - * @skip_setup_idle: if 1, do not idle hwmods in _setup() * * 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. */ -int omap_hwmod_late_init(u8 skip_setup_idle) +int omap_hwmod_late_init(void) { int r; @@ -1588,10 +1598,7 @@ int omap_hwmod_late_init(u8 skip_setup_idle) WARN(!mpu_oh, "omap_hwmod: could not find MPU initiator hwmod %s\n", MPU_INITIATOR_NAME); - if (skip_setup_idle) - pr_debug("omap_hwmod: will leave hwmods enabled during setup\n"); - - omap_hwmod_for_each(_setup, &skip_setup_idle); + omap_hwmod_for_each(_setup, NULL); return 0; } @@ -2117,3 +2124,25 @@ int omap_hwmod_for_each_by_class(const char *classname, return ret; } + +/** + * omap_hwmod_set_postsetup_state - set the post-_setup() state for this hwmod + * @oh: struct omap_hwmod * + * @state: state that _setup() should leave the hwmod in + * + * XXX document + * + */ +int omap_hwmod_set_postsetup_state(struct omap_hwmod *oh, u8 state) +{ + if (!oh) + return -EINVAL; + + /* XXX insure valid @state passed in */ + + mutex_lock(&oh->_mutex); + oh->_postsetup_state = state; + mutex_unlock(&oh->_mutex); + + return 0; +} diff --git a/arch/arm/plat-omap/include/plat/omap_hwmod.h b/arch/arm/plat-omap/include/plat/omap_hwmod.h index 7eaa8ed..a566efc 100644 --- a/arch/arm/plat-omap/include/plat/omap_hwmod.h +++ b/arch/arm/plat-omap/include/plat/omap_hwmod.h @@ -415,14 +415,24 @@ struct omap_hwmod_omap4_prcm { * @name: name of the hwmod_class * @sysc: device SYSCONFIG/SYSSTATUS register data * @rev: revision of the IP class + * @pre_shutdown: fn ptr to be executed immediately prior to device shutdown * * Represent the class of a OMAP hardware "modules" (e.g. timer, * smartreflex, gpio, uart...) + * + * @pre_shutdown is a function that will be run immediately before + * hwmod clocks are disabled, etc. It is intended for use for hwmods + * like the MPU watchdog, which cannot be disabled with the standard + * omap_hwmod_shutdown(). The function should return 0 upon success, + * or some negative error upon failure. Returning an error will cause + * omap_hwmod_shutdown() to abort the device shutdown and return an + * error. */ struct omap_hwmod_class { const char *name; struct omap_hwmod_class_sysconfig *sysc; u32 rev; + int (*pre_shutdown)(struct omap_hwmod *oh); }; /** @@ -452,6 +462,7 @@ struct omap_hwmod_class { * @response_lat: device OCP response latency (in interface clock cycles) * @_int_flags: internal-use hwmod flags * @_state: internal-use hwmod state + * @_postsetup_state: internal-use state to leave the hwmod in after _setup() * @flags: hwmod flags (documented below) * @omap_chip: OMAP chips this hwmod is present on * @_mutex: mutex serializing operations on this hwmod @@ -500,6 +511,7 @@ struct omap_hwmod { u8 hwmods_cnt; u8 _int_flags; u8 _state; + u8 _postsetup_state; const struct omap_chip_id omap_chip; }; @@ -509,7 +521,7 @@ int omap_hwmod_unregister(struct omap_hwmod *oh); struct omap_hwmod *omap_hwmod_lookup(const char *name); int omap_hwmod_for_each(int (*fn)(struct omap_hwmod *oh, void *data), void *data); -int omap_hwmod_late_init(u8 skip_setup_idle); +int omap_hwmod_late_init(void); int omap_hwmod_enable(struct omap_hwmod *oh); int _omap_hwmod_enable(struct omap_hwmod *oh); @@ -556,6 +568,8 @@ int omap_hwmod_for_each_by_class(const char *classname, void *user), void *user); +int omap_hwmod_set_postsetup_state(struct omap_hwmod *oh, u8 state); + /* * Chip variant-specific hwmod init routines - XXX should be converted * to use initcalls once the initial boot ordering is straightened out