Operating Performance Points (OPP) Library

  1. 2009-2010 Nishanth Menon <nm@ti.com>, Texas Instruments Incorporated

1. Introduction

1.1 What is an Operating Performance Point (OPP)?

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 SoCneed to function at their highest performing frequency all the time. Tofacilitate this, sub-modules in a SoC are grouped into domains, allowing somedomains to run at lower voltage and frequency while other domains run atvoltage/frequency pairs that are higher.

The set of discrete tuples consisting of frequency and voltage pairs thatthe device will support per domain are called Operating Performance Points orOPPs.

As an example:

Let us consider an MPU device which supports the following:{300MHz at minimum voltage of 1V}, {800MHz at minimum voltage of 1.2V},{1GHz at minimum voltage of 1.3V}

We can represent these as three OPPs as the following {Hz, uV} tuples:

  • {300000000, 1000000}

  • {800000000, 1200000}

  • {1000000000, 1300000}

1.2 Operating Performance Points Library

OPP library provides a set of helper functions to organize and query the OPPinformation. The library is located in drivers/opp/ directory and the headeris located in include/linux/pm_opp.h. OPP library can be enabled by enablingCONFIG_PM_OPP from power management menuconfig menu. Certain SoCs such as TexasInstrument’s OMAP framework allows to optionally boot at a certain OPP withoutneeding 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       ->

OPP layer expects each domain to be represented by a unique device pointer. SoCframework registers a set of initial OPPs per device with the OPP layer. Thislist 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 safelyenabled by default in the system.

Note on OPP Availability

As the system proceeds to operate, SoC framework may choose to make certainOPPs available or not available on each device based on various externalfactors. Example usage: Thermal management or other exceptional situations whereSoC framework might choose to disable a higher frequency OPP to safely continueoperations until that OPP could be re-enabled if possible.

OPP library facilitates this concept in its implementation. The followingoperational functions operate only on available opps:dev_pm_opp_find_freq_{ceil, floor}, dev_pm_opp_get_voltage, dev_pm_opp_get_freq,dev_pm_opp_get_opp_count.

dev_pm_opp_find_freq_exact is meant to be used to find the opp pointerwhich can then be used for dev_pm_opp_enable/disable functions to make anopp available as required.

WARNING: Users of OPP library should refresh their availability count usingget_opp_count if dev_pm_opp_enable/disable functions are invoked for adevice, the exact mechanism to trigger these or the notification mechanismto other dependent subsystems such as cpufreq are left to the discretion ofthe SoC specific framework which uses the OPP library. Similar care needsto be taken care to refresh the cpufreq table in cases of these operations.

2. Initial OPP List Registration

The SoC implementation calls dev_pm_opp_add function iteratively to add OPPs perdevice. It is expected that the SoC framework will register the OPP entriesoptimally- typical numbers range to be less than 5. The list generated byregistering the OPPs is maintained by OPP library throughout the deviceoperation. The SoC framework can subsequently control the availability of theOPPs dynamically using the dev_pm_opp_enable / disable functions.

dev_pm_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 OPPis assumed to be available and control of its availability can be donewith the dev_pm_opp_enable/disable functions. OPP libraryinternally stores and manages this information in the dev_pm_opp struct.This function may be used by SoC framework to define a optimal listas per the demands of SoC usage environment.

WARNING:

Do not use this function in interrupt context.

Example:

soc_pm_init(){       /* Do things */       r = dev_pm_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 thefrequency back to the corresponding OPP, OPP library provides handy functionsto search the OPP list that OPP library internally manages. These searchfunctions return the matching pointer representing the opp if a match isfound, else returns error. These errors are expected to be handled by standarderror checks such asIS_ERR() and appropriate actions taken by the caller.

Callers of these functions shall calldev_pm_opp_put() after they have used theOPP. Otherwise the memory for the OPP will never get freed and result inmemleak.

dev_pm_opp_find_freq_exact

Search for an OPP based on anexact frequency andavailability. This function is especially useful to enable an OPP whichis not available by default.Example: In a case when SoC framework detects a situation where ahigher frequency could be made available, it can use this function tofind the OPP prior to call the dev_pm_opp_enable to actually makeit available:

opp = dev_pm_opp_find_freq_exact(dev, 1000000000, false);dev_pm_opp_put(opp);/* dont operate on the pointer.. just do a sanity check.. */if (IS_ERR(opp)) {       pr_err("frequency not disabled!\n");       /* trigger appropriate actions.. */} else {       dev_pm_opp_enable(dev,1000000000);}
NOTE:

This is the only search function that operates on OPPs which arenot available.

dev_pm_opp_find_freq_floor

Search for an available OPP which isat most theprovided frequency. This function is useful while searching for a lessermatch OR operating on OPP information in the order of decreasingfrequency.Example: To find the highest opp for a device:

freq = ULONG_MAX;opp = dev_pm_opp_find_freq_floor(dev, &freq);dev_pm_opp_put(opp);
dev_pm_opp_find_freq_ceil

Search for an available OPP which isat least theprovided frequency. This function is useful while searching for ahigher match OR operating on OPP information in the order of increasingfrequency.Example 1: To find the lowest opp for a device:

freq = 0;opp = dev_pm_opp_find_freq_ceil(dev, &freq);dev_pm_opp_put(opp);

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 */       opp = dev_pm_opp_find_freq_ceil(dev, &freq);       dev_pm_opp_put(opp);       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 possiblesituation. The OPP library provides a set of functions to modify theavailability of a OPP within the OPP list. This allows SoC frameworks to havefine grained dynamic control of which sets of OPPs are operationally available.These functions are intended totemporarily remove an OPP in conditions suchas thermal considerations (e.g. don’t use OPPx until the temperature drops).

WARNING:

Do not use these functions in interrupt context.

dev_pm_opp_enable

Make a OPP available for operation.Example: Lets say that 1GHz OPP is to be made available only if theSoC temperature is lower than a certain threshold. The SoC frameworkimplementation might choose to do something as follows:

if (cur_temp < temp_low_thresh) {       /* Enable 1GHz if it was disabled */       opp = dev_pm_opp_find_freq_exact(dev, 1000000000, false);       dev_pm_opp_put(opp);       /* just error check */       if (!IS_ERR(opp))               ret = dev_pm_opp_enable(dev, 1000000000);       else               goto try_something_else;}
dev_pm_opp_disable

Make an OPP to be not available for operationExample: Lets say that 1GHz OPP is to be disabled if the temperatureexceeds a threshold value. The SoC framework implementation mightchoose to do something as follows:

if (cur_temp > temp_high_thresh) {       /* Disable 1GHz if it was enabled */       opp = dev_pm_opp_find_freq_exact(dev, 1000000000, true);       dev_pm_opp_put(opp);       /* just error check */       if (!IS_ERR(opp))               ret = dev_pm_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 pullinformation from the dev_pm_opp structure is necessary. Once an OPP pointer isretrieved using the search functions, the following functions can be used by SoCframework to retrieve the information represented inside the OPP layer.

dev_pm_opp_get_voltage

Retrieve the voltage represented by the opp pointer.Example: At a cpufreq transition to a different frequency, SoCframework requires to set the voltage represented by the OPP usingthe regulator framework to the Power Management chip providing thevoltage:

soc_switch_to_freq_voltage(freq){       /* do things */       opp = dev_pm_opp_find_freq_ceil(dev, &freq);       v = dev_pm_opp_get_voltage(opp);       dev_pm_opp_put(opp);       if (v)               regulator_set_voltage(.., v);       /* do other things */}
dev_pm_opp_get_freq

Retrieve the freq represented by the opp pointer.Example: Lets say the SoC framework uses a couple of helper functionswe could pass opp pointers instead of doing additional parameters tohandle quiet a bit of data parameters:

soc_cpufreq_target(..){       /* do things.. */        max_freq = ULONG_MAX;        max_opp = dev_pm_opp_find_freq_floor(dev,&max_freq);        requested_opp = dev_pm_opp_find_freq_ceil(dev,&freq);        if (!IS_ERR(max_opp) && !IS_ERR(requested_opp))               r = soc_test_validity(max_opp, requested_opp);        dev_pm_opp_put(max_opp);        dev_pm_opp_put(requested_opp);       /* do other things */}soc_test_validity(..){        if(dev_pm_opp_get_voltage(max_opp) < dev_pm_opp_get_voltage(requested_opp))                return -EINVAL;        if(dev_pm_opp_get_freq(max_opp) < dev_pm_opp_get_freq(requested_opp))                return -EINVAL;       /* do things.. */}
dev_pm_opp_get_opp_count

Retrieve the number of available opps for a deviceExample: Lets say a co-processor in the SoC needs to know the availablefrequencies in a table, the main processor can notify as following:

soc_notify_coproc_available_frequencies(){       /* Do things */       num_available = dev_pm_opp_get_opp_count(dev);       speeds = kcalloc(num_available, sizeof(u32), GFP_KERNEL);       /* populate the table in increasing order */       freq = 0;       while (!IS_ERR(opp = dev_pm_opp_find_freq_ceil(dev, &freq))) {               speeds[i] = freq;               freq++;               i++;               dev_pm_opp_put(opp);       }       soc_notify_coproc(AVAILABLE_FREQs, speeds, num_available);       /* Do other things */}

6. Data Structures

Typically an SoC contains multiple voltage domains which are variable. Eachdomain is represented by a device pointer. The relationship to OPP can berepresented 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 andaccessed by various functions as described above. However, the structuresrepresenting the actual OPPs and domains are internal to the OPP library itselfto allow for suitable abstraction reusable across systems.

struct dev_pm_opp

The internal data structure of OPP library which is used torepresent an OPP. In addition to the freq, voltage, availabilityinformation, it also contains internal book keeping information requiredfor the OPP library to operate on. Pointer to this structure isprovided back to the users such as SoC framework to be used as aidentifier for OPP in the interactions with OPP layer.

WARNING:

Thestructdev_pm_opp pointer should not be parsed or modified by theusers. The defaults of for an instance is populated bydev_pm_opp_add, but the availability of the OPP can be modifiedby dev_pm_opp_enable/disable functions.

struct device

This is used to identify a domain to the OPP layer. Thenature of the device and its implementation is left to the user ofOPP library such as the SoC framework.

Overall, in a simplistic view, the data structure operations is represented asfollowing:

Initialization / modification:            +-----+        /- dev_pm_opp_enabledev_pm_opp_add --> | opp | <-------  |         +-----+        \- dev_pm_opp_disable  \-------> domain_info(device)Search functions:             /-- dev_pm_opp_find_freq_ceil  ---\   +-----+domain_info<---- dev_pm_opp_find_freq_exact -----> | opp |             \-- dev_pm_opp_find_freq_floor ---/   +-----+Retrieval functions:+-----+     /- dev_pm_opp_get_voltage| opp | <---+-----+     \- dev_pm_opp_get_freqdomain_info <- dev_pm_opp_get_opp_count