| 
					
				 | 
			
			
				@@ -1993,3 +1993,200 @@ static int _reset(struct omap_hwmod *oh) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 /** 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  * _reconfigure_io_chain - clear any I/O chain wakeups and reconfigure chain 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  * 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ * Call the appropriate PRM function to clear any logged I/O chain 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ * wakeups and to reconfigure the chain.  This apparently needs to be 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ * done upon every mux change.  Since hwmods can be concurrently 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ * enabled and idled, hold a spinlock around the I/O chain 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ * reconfiguration sequence.  No return value. 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ * 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ * XXX When the PRM code is moved to drivers, this function can be removed, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ * as the PRM infrastructure should abstract this. 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+static void _reconfigure_io_chain(void) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+{ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	unsigned long flags; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	spin_lock_irqsave(&io_chain_lock, flags); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	if (cpu_is_omap34xx() && omap3_has_io_chain_ctrl()) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		omap3xxx_prm_reconfigure_io_chain(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	else if (cpu_is_omap44xx()) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		omap44xx_prm_reconfigure_io_chain(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	spin_unlock_irqrestore(&io_chain_lock, flags); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+/** 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ * _omap4_update_context_lost - increment hwmod context loss counter if 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ * hwmod context was lost, and clear hardware context loss reg 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ * @oh: hwmod to check for context loss 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ * 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ * If the PRCM indicates that the hwmod @oh lost context, increment 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ * our in-memory context loss counter, and clear the RM_*_CONTEXT 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ * bits. No return value. 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+static void _omap4_update_context_lost(struct omap_hwmod *oh) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+{ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	if (oh->prcm.omap4.flags & HWMOD_OMAP4_NO_CONTEXT_LOSS_BIT) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		return; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	if (!prm_was_any_context_lost_old(oh->clkdm->pwrdm.ptr->prcm_partition, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+					  oh->clkdm->pwrdm.ptr->prcm_offs, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+					  oh->prcm.omap4.context_offs)) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		return; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	oh->prcm.omap4.context_lost_counter++; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	prm_clear_context_loss_flags_old(oh->clkdm->pwrdm.ptr->prcm_partition, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+					 oh->clkdm->pwrdm.ptr->prcm_offs, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+					 oh->prcm.omap4.context_offs); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+/** 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ * _omap4_get_context_lost - get context loss counter for a hwmod 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ * @oh: hwmod to get context loss counter for 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ * 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ * Returns the in-memory context loss counter for a hwmod. 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+static int _omap4_get_context_lost(struct omap_hwmod *oh) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+{ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	return oh->prcm.omap4.context_lost_counter; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+/** 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ * _enable - enable an omap_hwmod 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ * @oh: struct omap_hwmod * 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ * 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ * Enables an omap_hwmod @oh such that the MPU can access the hwmod's 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ * register target.  Returns -EINVAL if the hwmod is in the wrong 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ * state or passes along the return value of _wait_target_ready(). 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+static int _enable(struct omap_hwmod *oh) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+{ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	int r; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	int hwsup = 0; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	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. 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	 */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	if (oh->_int_flags & _HWMOD_SKIP_ENABLE) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		/* 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		 * If the caller has mux data populated, do the mux'ing 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		 * which wouldn't have been done as part of the _enable() 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		 * done during setup. 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		 */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		if (oh->mux) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			omap_hwmod_mux(oh->mux, _HWMOD_STATE_ENABLED); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		oh->_int_flags &= ~_HWMOD_SKIP_ENABLE; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		return 0; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	if (oh->_state != _HWMOD_STATE_INITIALIZED && 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	    oh->_state != _HWMOD_STATE_IDLE && 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	    oh->_state != _HWMOD_STATE_DISABLED) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		WARN(1, "omap_hwmod: %s: enabled state can only be entered from initialized, idle, or disabled state\n", 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			oh->name); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		return -EINVAL; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	/* 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	 * If an IP block contains HW reset lines and all 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 (_are_all_hardreset_lines_asserted(oh)) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		return 0; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	/* Mux pins for device runtime if populated */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	if (oh->mux && (!oh->mux->enabled || 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			((oh->_state == _HWMOD_STATE_IDLE) && 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			 oh->mux->pads_dynamic))) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		omap_hwmod_mux(oh->mux, _HWMOD_STATE_ENABLED); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		_reconfigure_io_chain(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	_add_initiator_dep(oh, mpu_oh); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	if (oh->clkdm) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		/* 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		 * A clockdomain must be in SW_SUP before enabling 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		 * completely the module. The clockdomain can be set 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		 * in HW_AUTO only when the module become ready. 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		 */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		hwsup = clkdm_in_hwsup(oh->clkdm) && 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			!clkdm_missing_idle_reporting(oh->clkdm); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		r = clkdm_hwmod_enable(oh->clkdm, oh); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		if (r) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			WARN(1, "omap_hwmod: %s: could not enable clockdomain %s: %d\n", 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			     oh->name, oh->clkdm->name, r); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			return r; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	_enable_clocks(oh); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	if (soc_ops.enable_module) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		soc_ops.enable_module(oh); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	if (soc_ops.update_context_lost) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		soc_ops.update_context_lost(oh); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	r = (soc_ops.wait_target_ready) ? soc_ops.wait_target_ready(oh) : 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		-EINVAL; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	if (!r) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		/* 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		 * Set the clockdomain to HW_AUTO only if the target is ready, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		 * assuming that the previous state was HW_AUTO 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		 */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		if (oh->clkdm && hwsup) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			clkdm_allow_idle(oh->clkdm); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		oh->_state = _HWMOD_STATE_ENABLED; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		/* Access the sysconfig only if the target is ready */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		if (oh->class->sysc) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			if (!(oh->_int_flags & _HWMOD_SYSCONFIG_LOADED)) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+				_update_sysc_cache(oh); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			_enable_sysc(oh); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	} else { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		if (soc_ops.disable_module) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			soc_ops.disable_module(oh); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		_disable_clocks(oh); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		pr_debug("omap_hwmod: %s: _wait_target_ready: %d\n", 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			 oh->name, r); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		if (oh->clkdm) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			clkdm_hwmod_disable(oh->clkdm, oh); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	return r; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+/** 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ * _idle - idle an omap_hwmod 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ * @oh: struct omap_hwmod * 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ * 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ * Idles an omap_hwmod @oh.  This should be called once the hwmod has 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ * no further work.  Returns -EINVAL if the hwmod is in the wrong 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ * state or returns 0. 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+static int _idle(struct omap_hwmod *oh) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+{ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	pr_debug("omap_hwmod: %s: idling\n", oh->name); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	if (oh->_state != _HWMOD_STATE_ENABLED) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		WARN(1, "omap_hwmod: %s: idle state can only be entered from enabled state\n", 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			oh->name); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		return -EINVAL; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	if (_are_all_hardreset_lines_asserted(oh)) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		return 0; 
			 |