Fixes generated by 'codespell' and manually reviewed. Signed-off-by: Lucas De Marchi <lucas.demarchi@profusion.mobi>
		
			
				
	
	
		
			379 lines
		
	
	
		
			14 KiB
		
	
	
	
		
			Plaintext
		
	
	
	
	
	
			
		
		
	
	
			379 lines
		
	
	
		
			14 KiB
		
	
	
	
		
			Plaintext
		
	
	
	
	
	
| *=============*
 | |
| * OPP Library *
 | |
| *=============*
 | |
| 
 | |
| (C) 2009-2010 Nishanth Menon <nm@ti.com>, Texas Instruments Incorporated
 | |
| 
 | |
| Contents
 | |
| --------
 | |
| 1. Introduction
 | |
| 2. Initial OPP List Registration
 | |
| 3. OPP Search Functions
 | |
| 4. OPP Availability Control Functions
 | |
| 5. OPP Data Retrieval Functions
 | |
| 6. Cpufreq Table Generation
 | |
| 7. Data Structures
 | |
| 
 | |
| 1. Introduction
 | |
| ===============
 | |
| Complex SoCs of today consists of a multiple sub-modules working in conjunction.
 | |
| In an operational system executing varied use cases, not all modules in the SoC
 | |
| need to function at their highest performing frequency all the time. To
 | |
| facilitate this, sub-modules in a SoC are grouped into domains, allowing some
 | |
| domains to run at lower voltage and frequency while other domains are loaded
 | |
| more. The set of discrete tuples consisting of frequency and voltage pairs that
 | |
| the device will support per domain are called Operating Performance Points or
 | |
| OPPs.
 | |
| 
 | |
| OPP library provides a set of helper functions to organize and query the OPP
 | |
| information. The library is located in drivers/base/power/opp.c and the header
 | |
| is located in include/linux/opp.h. OPP library can be enabled by enabling
 | |
| CONFIG_PM_OPP from power management menuconfig menu. OPP library depends on
 | |
| CONFIG_PM as certain SoCs such as Texas Instrument's OMAP framework allows to
 | |
| optionally boot at a certain OPP without needing cpufreq.
 | |
| 
 | |
| Typical usage of the OPP library is as follows:
 | |
| (users)		-> registers a set of default OPPs		-> (library)
 | |
| SoC framework	-> modifies on required cases certain OPPs	-> OPP layer
 | |
| 		-> queries to search/retrieve information	->
 | |
| 
 | |
| Architectures that provide a SoC framework for OPP should select ARCH_HAS_OPP
 | |
| to make the OPP layer available.
 | |
| 
 | |
| OPP layer expects each domain to be represented by a unique device pointer. SoC
 | |
| framework registers a set of initial OPPs per device with the OPP layer. This
 | |
| list is expected to be an optimally small number typically around 5 per device.
 | |
| This initial list contains a set of OPPs that the framework expects to be safely
 | |
| enabled by default in the system.
 | |
| 
 | |
| Note on OPP Availability:
 | |
| ------------------------
 | |
| As the system proceeds to operate, SoC framework may choose to make certain
 | |
| OPPs available or not available on each device based on various external
 | |
| factors. Example usage: Thermal management or other exceptional situations where
 | |
| SoC framework might choose to disable a higher frequency OPP to safely continue
 | |
| operations until that OPP could be re-enabled if possible.
 | |
| 
 | |
| OPP library facilitates this concept in it's implementation. The following
 | |
| operational functions operate only on available opps:
 | |
| opp_find_freq_{ceil, floor}, opp_get_voltage, opp_get_freq, opp_get_opp_count
 | |
| and opp_init_cpufreq_table
 | |
| 
 | |
| opp_find_freq_exact is meant to be used to find the opp pointer which can then
 | |
| be used for opp_enable/disable functions to make an opp available as required.
 | |
| 
 | |
| WARNING: Users of OPP library should refresh their availability count using
 | |
| get_opp_count if opp_enable/disable functions are invoked for a device, the
 | |
| exact mechanism to trigger these or the notification mechanism to other
 | |
| dependent subsystems such as cpufreq are left to the discretion of the SoC
 | |
| specific framework which uses the OPP library. Similar care needs to be taken
 | |
| care to refresh the cpufreq table in cases of these operations.
 | |
| 
 | |
| WARNING on OPP List locking mechanism:
 | |
| -------------------------------------------------
 | |
| OPP library uses RCU for exclusivity. RCU allows the query functions to operate
 | |
| in multiple contexts and this synchronization mechanism is optimal for a read
 | |
| intensive operations on data structure as the OPP library caters to.
 | |
| 
 | |
| To ensure that the data retrieved are sane, the users such as SoC framework
 | |
| should ensure that the section of code operating on OPP queries are locked
 | |
| using RCU read locks. The opp_find_freq_{exact,ceil,floor},
 | |
| opp_get_{voltage, freq, opp_count} fall into this category.
 | |
| 
 | |
| opp_{add,enable,disable} are updaters which use mutex and implement it's own
 | |
| RCU locking mechanisms. opp_init_cpufreq_table acts as an updater and uses
 | |
| mutex to implment RCU updater strategy. These functions should *NOT* be called
 | |
| under RCU locks and other contexts that prevent blocking functions in RCU or
 | |
| mutex operations from working.
 | |
| 
 | |
| 2. Initial OPP List Registration
 | |
| ================================
 | |
| The SoC implementation calls opp_add function iteratively to add OPPs per
 | |
| device. It is expected that the SoC framework will register the OPP entries
 | |
| optimally- typical numbers range to be less than 5. The list generated by
 | |
| registering the OPPs is maintained by OPP library throughout the device
 | |
| operation. The SoC framework can subsequently control the availability of the
 | |
| OPPs dynamically using the opp_enable / disable functions.
 | |
| 
 | |
| opp_add - Add a new OPP for a specific domain represented by the device pointer.
 | |
| 	The OPP is defined using the frequency and voltage. Once added, the OPP
 | |
| 	is assumed to be available and control of it's availability can be done
 | |
| 	with the opp_enable/disable functions. OPP library internally stores
 | |
| 	and manages this information in the opp struct. This function may be
 | |
| 	used by SoC framework to define a optimal list as per the demands of
 | |
| 	SoC usage environment.
 | |
| 
 | |
| 	WARNING: Do not use this function in interrupt context.
 | |
| 
 | |
| 	Example:
 | |
| 	 soc_pm_init()
 | |
| 	 {
 | |
| 		/* Do things */
 | |
| 		r = opp_add(mpu_dev, 1000000, 900000);
 | |
| 		if (!r) {
 | |
| 			pr_err("%s: unable to register mpu opp(%d)\n", r);
 | |
| 			goto no_cpufreq;
 | |
| 		}
 | |
| 		/* Do cpufreq things */
 | |
| 	 no_cpufreq:
 | |
| 		/* Do remaining things */
 | |
| 	 }
 | |
| 
 | |
| 3. OPP Search Functions
 | |
| =======================
 | |
| High level framework such as cpufreq operates on frequencies. To map the
 | |
| frequency back to the corresponding OPP, OPP library provides handy functions
 | |
| to search the OPP list that OPP library internally manages. These search
 | |
| functions return the matching pointer representing the opp if a match is
 | |
| found, else returns error. These errors are expected to be handled by standard
 | |
| error checks such as IS_ERR() and appropriate actions taken by the caller.
 | |
| 
 | |
| opp_find_freq_exact - Search for an OPP based on an *exact* frequency and
 | |
| 	availability. This function is especially useful to enable an OPP which
 | |
| 	is not available by default.
 | |
| 	Example: In a case when SoC framework detects a situation where a
 | |
| 	higher frequency could be made available, it can use this function to
 | |
| 	find the OPP prior to call the opp_enable to actually make it available.
 | |
| 	 rcu_read_lock();
 | |
| 	 opp = opp_find_freq_exact(dev, 1000000000, false);
 | |
| 	 rcu_read_unlock();
 | |
| 	 /* dont operate on the pointer.. just do a sanity check.. */
 | |
| 	 if (IS_ERR(opp)) {
 | |
| 		pr_err("frequency not disabled!\n");
 | |
| 		/* trigger appropriate actions.. */
 | |
| 	 } else {
 | |
| 		opp_enable(dev,1000000000);
 | |
| 	 }
 | |
| 
 | |
| 	NOTE: This is the only search function that operates on OPPs which are
 | |
| 	not available.
 | |
| 
 | |
| opp_find_freq_floor - Search for an available OPP which is *at most* the
 | |
| 	provided frequency. This function is useful while searching for a lesser
 | |
| 	match OR operating on OPP information in the order of decreasing
 | |
| 	frequency.
 | |
| 	Example: To find the highest opp for a device:
 | |
| 	 freq = ULONG_MAX;
 | |
| 	 rcu_read_lock();
 | |
| 	 opp_find_freq_floor(dev, &freq);
 | |
| 	 rcu_read_unlock();
 | |
| 
 | |
| opp_find_freq_ceil - Search for an available OPP which is *at least* the
 | |
| 	provided frequency. This function is useful while searching for a
 | |
| 	higher match OR operating on OPP information in the order of increasing
 | |
| 	frequency.
 | |
| 	Example 1: To find the lowest opp for a device:
 | |
| 	 freq = 0;
 | |
| 	 rcu_read_lock();
 | |
| 	 opp_find_freq_ceil(dev, &freq);
 | |
| 	 rcu_read_unlock();
 | |
| 	Example 2: A simplified implementation of a SoC cpufreq_driver->target:
 | |
| 	 soc_cpufreq_target(..)
 | |
| 	 {
 | |
| 		/* Do stuff like policy checks etc. */
 | |
| 		/* Find the best frequency match for the req */
 | |
| 		rcu_read_lock();
 | |
| 		opp = opp_find_freq_ceil(dev, &freq);
 | |
| 		rcu_read_unlock();
 | |
| 		if (!IS_ERR(opp))
 | |
| 			soc_switch_to_freq_voltage(freq);
 | |
| 		else
 | |
| 			/* do something when we can't satisfy the req */
 | |
| 		/* do other stuff */
 | |
| 	 }
 | |
| 
 | |
| 4. OPP Availability Control Functions
 | |
| =====================================
 | |
| A default OPP list registered with the OPP library may not cater to all possible
 | |
| situation. The OPP library provides a set of functions to modify the
 | |
| availability of a OPP within the OPP list. This allows SoC frameworks to have
 | |
| fine grained dynamic control of which sets of OPPs are operationally available.
 | |
| These functions are intended to *temporarily* remove an OPP in conditions such
 | |
| as thermal considerations (e.g. don't use OPPx until the temperature drops).
 | |
| 
 | |
| WARNING: Do not use these functions in interrupt context.
 | |
| 
 | |
| opp_enable - Make a OPP available for operation.
 | |
| 	Example: Lets say that 1GHz OPP is to be made available only if the
 | |
| 	SoC temperature is lower than a certain threshold. The SoC framework
 | |
| 	implementation might choose to do something as follows:
 | |
| 	 if (cur_temp < temp_low_thresh) {
 | |
| 		/* Enable 1GHz if it was disabled */
 | |
| 		rcu_read_lock();
 | |
| 		opp = opp_find_freq_exact(dev, 1000000000, false);
 | |
| 		rcu_read_unlock();
 | |
| 		/* just error check */
 | |
| 		if (!IS_ERR(opp))
 | |
| 			ret = opp_enable(dev, 1000000000);
 | |
| 		else
 | |
| 			goto try_something_else;
 | |
| 	 }
 | |
| 
 | |
| opp_disable - Make an OPP to be not available for operation
 | |
| 	Example: Lets say that 1GHz OPP is to be disabled if the temperature
 | |
| 	exceeds a threshold value. The SoC framework implementation might
 | |
| 	choose to do something as follows:
 | |
| 	 if (cur_temp > temp_high_thresh) {
 | |
| 		/* Disable 1GHz if it was enabled */
 | |
| 		rcu_read_lock();
 | |
| 		opp = opp_find_freq_exact(dev, 1000000000, true);
 | |
| 		rcu_read_unlock();
 | |
| 		/* just error check */
 | |
| 		if (!IS_ERR(opp))
 | |
| 			ret = opp_disable(dev, 1000000000);
 | |
| 		else
 | |
| 			goto try_something_else;
 | |
| 	 }
 | |
| 
 | |
| 5. OPP Data Retrieval Functions
 | |
| ===============================
 | |
| Since OPP library abstracts away the OPP information, a set of functions to pull
 | |
| information from the OPP structure is necessary. Once an OPP pointer is
 | |
| retrieved using the search functions, the following functions can be used by SoC
 | |
| framework to retrieve the information represented inside the OPP layer.
 | |
| 
 | |
| opp_get_voltage - Retrieve the voltage represented by the opp pointer.
 | |
| 	Example: At a cpufreq transition to a different frequency, SoC
 | |
| 	framework requires to set the voltage represented by the OPP using
 | |
| 	the regulator framework to the Power Management chip providing the
 | |
| 	voltage.
 | |
| 	 soc_switch_to_freq_voltage(freq)
 | |
| 	 {
 | |
| 		/* do things */
 | |
| 		rcu_read_lock();
 | |
| 		opp = opp_find_freq_ceil(dev, &freq);
 | |
| 		v = opp_get_voltage(opp);
 | |
| 		rcu_read_unlock();
 | |
| 		if (v)
 | |
| 			regulator_set_voltage(.., v);
 | |
| 		/* do other things */
 | |
| 	 }
 | |
| 
 | |
| opp_get_freq - Retrieve the freq represented by the opp pointer.
 | |
| 	Example: Lets say the SoC framework uses a couple of helper functions
 | |
| 	we could pass opp pointers instead of doing additional parameters to
 | |
| 	handle quiet a bit of data parameters.
 | |
| 	 soc_cpufreq_target(..)
 | |
| 	 {
 | |
| 		/* do things.. */
 | |
| 		 max_freq = ULONG_MAX;
 | |
| 		 rcu_read_lock();
 | |
| 		 max_opp = opp_find_freq_floor(dev,&max_freq);
 | |
| 		 requested_opp = opp_find_freq_ceil(dev,&freq);
 | |
| 		 if (!IS_ERR(max_opp) && !IS_ERR(requested_opp))
 | |
| 			r = soc_test_validity(max_opp, requested_opp);
 | |
| 		 rcu_read_unlock();
 | |
| 		/* do other things */
 | |
| 	 }
 | |
| 	 soc_test_validity(..)
 | |
| 	 {
 | |
| 		 if(opp_get_voltage(max_opp) < opp_get_voltage(requested_opp))
 | |
| 			 return -EINVAL;
 | |
| 		 if(opp_get_freq(max_opp) < opp_get_freq(requested_opp))
 | |
| 			 return -EINVAL;
 | |
| 		/* do things.. */
 | |
| 	 }
 | |
| 
 | |
| opp_get_opp_count - Retrieve the number of available opps for a device
 | |
| 	Example: Lets say a co-processor in the SoC needs to know the available
 | |
| 	frequencies in a table, the main processor can notify as following:
 | |
| 	 soc_notify_coproc_available_frequencies()
 | |
| 	 {
 | |
| 		/* Do things */
 | |
| 		rcu_read_lock();
 | |
| 		num_available = opp_get_opp_count(dev);
 | |
| 		speeds = kzalloc(sizeof(u32) * num_available, GFP_KERNEL);
 | |
| 		/* populate the table in increasing order */
 | |
| 		freq = 0;
 | |
| 		while (!IS_ERR(opp = opp_find_freq_ceil(dev, &freq))) {
 | |
| 			speeds[i] = freq;
 | |
| 			freq++;
 | |
| 			i++;
 | |
| 		}
 | |
| 		rcu_read_unlock();
 | |
| 
 | |
| 		soc_notify_coproc(AVAILABLE_FREQs, speeds, num_available);
 | |
| 		/* Do other things */
 | |
| 	 }
 | |
| 
 | |
| 6. Cpufreq Table Generation
 | |
| ===========================
 | |
| opp_init_cpufreq_table - cpufreq framework typically is initialized with
 | |
| 	cpufreq_frequency_table_cpuinfo which is provided with the list of
 | |
| 	frequencies that are available for operation. This function provides
 | |
| 	a ready to use conversion routine to translate the OPP layer's internal
 | |
| 	information about the available frequencies into a format readily
 | |
| 	providable to cpufreq.
 | |
| 
 | |
| 	WARNING: Do not use this function in interrupt context.
 | |
| 
 | |
| 	Example:
 | |
| 	 soc_pm_init()
 | |
| 	 {
 | |
| 		/* Do things */
 | |
| 		r = opp_init_cpufreq_table(dev, &freq_table);
 | |
| 		if (!r)
 | |
| 			cpufreq_frequency_table_cpuinfo(policy, freq_table);
 | |
| 		/* Do other things */
 | |
| 	 }
 | |
| 
 | |
| 	NOTE: This function is available only if CONFIG_CPU_FREQ is enabled in
 | |
| 	addition to CONFIG_PM as power management feature is required to
 | |
| 	dynamically scale voltage and frequency in a system.
 | |
| 
 | |
| 7. Data Structures
 | |
| ==================
 | |
| Typically an SoC contains multiple voltage domains which are variable. Each
 | |
| domain is represented by a device pointer. The relationship to OPP can be
 | |
| represented as follows:
 | |
| SoC
 | |
|  |- device 1
 | |
|  |	|- opp 1 (availability, freq, voltage)
 | |
|  |	|- opp 2 ..
 | |
|  ...	...
 | |
|  |	`- opp n ..
 | |
|  |- device 2
 | |
|  ...
 | |
|  `- device m
 | |
| 
 | |
| OPP library maintains a internal list that the SoC framework populates and
 | |
| accessed by various functions as described above. However, the structures
 | |
| representing the actual OPPs and domains are internal to the OPP library itself
 | |
| to allow for suitable abstraction reusable across systems.
 | |
| 
 | |
| struct opp - The internal data structure of OPP library which is used to
 | |
| 	represent an OPP. In addition to the freq, voltage, availability
 | |
| 	information, it also contains internal book keeping information required
 | |
| 	for the OPP library to operate on.  Pointer to this structure is
 | |
| 	provided back to the users such as SoC framework to be used as a
 | |
| 	identifier for OPP in the interactions with OPP layer.
 | |
| 
 | |
| 	WARNING: The struct opp pointer should not be parsed or modified by the
 | |
| 	users. The defaults of for an instance is populated by opp_add, but the
 | |
| 	availability of the OPP can be modified by opp_enable/disable functions.
 | |
| 
 | |
| struct device - This is used to identify a domain to the OPP layer. The
 | |
| 	nature of the device and it's implementation is left to the user of
 | |
| 	OPP library such as the SoC framework.
 | |
| 
 | |
| Overall, in a simplistic view, the data structure operations is represented as
 | |
| following:
 | |
| 
 | |
| Initialization / modification:
 | |
|             +-----+        /- opp_enable
 | |
| opp_add --> | opp | <-------
 | |
|   |         +-----+        \- opp_disable
 | |
|   \-------> domain_info(device)
 | |
| 
 | |
| Search functions:
 | |
|              /-- opp_find_freq_ceil  ---\   +-----+
 | |
| domain_info<---- opp_find_freq_exact -----> | opp |
 | |
|              \-- opp_find_freq_floor ---/   +-----+
 | |
| 
 | |
| Retrieval functions:
 | |
| +-----+     /- opp_get_voltage
 | |
| | opp | <---
 | |
| +-----+     \- opp_get_freq
 | |
| 
 | |
| domain_info <- opp_get_opp_count
 |