linux opp怎么使用

Posted Zephyr

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了linux opp怎么使用相关的知识,希望对你有一定的参考价值。

简介Operating Performance Points (OPP)

SoC是高度集成的,不是SoC中的所有模块需要一直以最高的频率运作。来为了便于实现这一点,SoC中的子模块被分组到不同的域中,允许一些域运行在较低的电压和频率,而其他域运行在更高的电压/频率对。

由频率和电压对组成的离散元组的集合称为工作性能点(opp)。

例如:让我们考虑一个支持以下功能的MPU设备:
300MHz,最小电压1V,
800MHz,最小电压1.2V,
最低电压1.3V时1GHz,

我们可以用Hz, uV元组来表示这三个opp:

300000000, 1000000
800000000, 1200000
1000000000, 1300000

OPP API接口

OPP库提供了一组辅助函数来组织和查询OPP信息。库位于drivers/opp/目录中,头文件位于include/linux/pm_opp.h中。可以通过从电源管理菜单CONFIG菜单启用CONFIG_pm_opp来启用opp库。某些SoC,如Texas Instrument的OMAP框架,允许在不需要cpufreq的情况下选择性地在某个OPP启动。

OPP层期望每个域由一个唯一的设备指针来表示。SoC框架在OPP层为每个设备注册一组初始OPP。这个列表的长度一般比较小,通常每个设备大约5个。这个初始列表包含一组 OPP,框架希望系统默认情况下能够安全地启用这些 OPP。

通常使用opp的方式有以下几步:
a. 用户为设备(比如CPU)配置/注册一些默认的opp信息。
b. Soc会根据具体的运行情况,通过opp层去改变/查询设备的opp信息。

(users)  -> registers a set of default OPPs  -> (library)

SoC framework -> modifies on required cases certain OPPs -> OPP layer ->queries to search/retrieve information 

使用OPP的场景

随着系统继续运行,SoC框架可能会根据各种外部因素选择在每个设备上提供某些 OPP 或不提供 OPP。
示例用法:热管理或其他特殊情况,SoC框架可能选择禁用更高频率的OPP以安全地继续操作,直到该OPP可以在可能的情况下重新启用。

警告:如果设备调用了dev_pm_opp_enable/deisable函数,则OPP库的用户应使用get_opp_count刷新其可用性计数,在进行这些操作的情况下,需要注意刷新cpufreq表。

如何使用OPP

OPP列表初始化

迭代调用dev_ pm_opp_ dd 函数为每个设备添加 OPP列表。每个设备的opp个数最好小于5个。

OPP是用频率和电压定义的。一旦完成添加,OPP被认为是可用的,可以用dev_pm_opp_enable/disable函数来控制其可用性。OPP库内部用dev_pm_opp结构体存储并管理这些信息。

注意:不要在中断上下文中使用此函数。

例如,多次调用dev_pm_opp_add为mpu_dev添加多个opp。

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 */

OPP查询获取函数

cpufreq等高层框架对频率进行操作,为了将频率映射到相应的OPP,OPP库提供了便利的函数来搜索OPP库内部管理的OPP链表。这些搜索函数如果找到匹配的OPP,将返回指向该OPP的指针,否则返回错误。这些错误预计由标准的错误检查,如IS_ERR()来处理,并由调用者采取适当的行动。

这些函数的调用者应在使用完OPP后调用dev_pm_opp_put()。否则,OPP的内存将永远不会被释放,并导致内存泄露。

函数 作用
dev_pm_opp_find_freq_ceil, dev_pm_opp_find_freq_floor 查找某个频率附近的最高频率,或者最低频率
dev_pm_opp_find_freq_exact 此功能对于启用默认情况下不可用的OPP特别有用

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 */

OPP可用性控制功能

dev_pm_opp_enable:使OPP可用。示例:假设只有当SoC温度低于某个阈值时,1GHz OPP才可用

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: OPP不可用于。示例: 如果温度超过阈值,则禁用1GHz OPP。

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;

OPP数据检索功能

dev_pm_opp_get_voltage:检索opp指针表示的电压。示例:在cpufreq转换到不同频率时,需要使用regulator框架将由OPP表示的电压来配置到pmic:

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:检索opp指针表示的频率。例如:假设SoC框架使用了几个辅助函数,我们可以传递opp指针,而不是做额外的参数来处理一些安静的数据参数:

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:检索设备的可用opp数量示例:假设SoC中的协同处理器需要知道表中的可用频率,主处理器可以通知如下:

soc_notify_coproc_available_frequencies()

       /* Do things */
       num_available = dev_pm_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 = 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 */

OPP数据结构

通常,一个SoC包含多个可变电压域。每个域由一个设备指针描述。和OPP之间的关系可以按以下方式描述::

SoC
 |- device 1
 |    |- opp 1 (availability, freq, voltage)
 |    |- opp 2 ..
 ...  ...
 |    `- opp n ..
 |- device 2
 ...
 `- device m

OPP库维护着一个内部链表,SoC框架使用上文描述的各个函数来填充和访问。然而,描述真实OPP和域的结构体是OPP库自身的内部组成,以允许合适的抽象在不同系统中得到复用。

struct dev_pm_opp
OPP库的内部数据结构,用于表示一个OPP。除了频率、电压、可用性信息外,它还包含OPP库运行所需的内部统计信息。指向这个结构体的指针被提供给用户(比如SoC框架)使用,在与OPP层的交互中作为OPP的标识符。

警告:结构体dev_pm_opp的指针不应该由用户解析或修改。一个实例的默认值由dev_pm_opp_add填充,但OPP的可用性由dev_pm_opp_enable/disable函数修改。

struct device
这用于向OPP层标识一个域。设备的性质和它的实现是由OPP库的用户决定的,如SoC框架。
总体来说,以一个简化的视角看,对数据结构的操作可以描述为下面各图::

初始化和修改相关:
            +-----+        /- dev_pm_opp_enable
dev_pm_opp_add --> | opp | <-------
  |         +-----+        \\- dev_pm_opp_disable
  \\-------> domain_info(device)

查找函数:
             /-- dev_pm_opp_find_freq_ceil  ---\\   +-----+
domain_info<---- dev_pm_opp_find_freq_exact -----> | opp |
             \\-- dev_pm_opp_find_freq_floor ---/   +-----+

检索函数:
+-----+     /- dev_pm_opp_get_voltage
| opp | <---
+-----+     \\- dev_pm_opp_get_freq

domain_info <- dev_pm_opp_get_opp_count

OPP的DTS配置

Ref

https://docs.kernel.org/power/opp.html

OBEX OPP 特定转账

【中文标题】OBEX OPP 特定转账【英文标题】:OBEX OPP Specific transfer 【发布时间】:2011-09-05 09:13:02 【问题描述】:

我正在android中开发一个OBEX OPP客户端应用程序 电话。通过客户端应用程序 我将向非 Android 设备发送一个对象(它将充当 OPP 服务器)。我已经使用 API 创建了 RFCOMM 套接字连接

createRfcommSocketToServiceRecord(OPP_UUID);我已经使用了 UUID OBEX Push 即

私有静态最终 UUID OPP_UUID = UUID .fromString("00001105-0000-1000-8000-00805F9B34FB");

我观察到通过这个socket连接是成功的 我得到了要发送的套接字的输入和输出流 接收数据。但是当我发送数据时,数据收到了另一个 设备格式不正确。我的意思是在 接收器设备接收到的数据有错误。 BT 空气嗅探器 表示retrieved_opcode中的数据不存在。OBEX 响应代码是错误请求。

谁能指导我这有什么问题?或制作步骤 OBEX OPP 与未配对设备的连接。

您的宝贵意见将帮助我克服这个问题。

谢谢, 谢卡尔

【问题讨论】:

【参考方案1】:

您应该可以配对设备,您也可以通过设备上的蓝牙设置进行配对,但您无法与它连接并像SPP通信那样直接发送数据。

OBEX是一个协议,有自己的头、包等。

Android 中没有可以通过编程方式使用的通过 OBEX 进行通信的 API。 (你可以连接到设备,但你只能读/写字节)。

您可以通过以下几种方式通过 obex 将文件发送到配对设备:

使用 ACTION_SEND 意图,将弹出一个菜单,其中包含可以处理您要发送的文件类型的应用程序,用户需要从中选择蓝牙,然后选择设备。

Intent share = new Intent(Intent.ACTION_SEND);
share.setType("image/jpeg");
share.putExtra(Intent.EXTRA_STREAM, Uri.parse(SDCardPath + "file.jpg"));
startActivity(Intent.createChooser(share, "Share Image"));

或者,如果您不希望应用程序中出现任何对话框,您也可以使用其他方法,检查以下问题,它有一个有效解决方案的更新:

Sending a File using Bluetooth OBEX Object Push Profile (OPP)

【讨论】:

以上是关于linux opp怎么使用的主要内容,如果未能解决你的问题,请参考以下文章

php--opp--7.特殊的引用”$this“的使用

Linux内核dvfs之cpufreq配置

理解面向过程(OPP)面向对象(OOP)面向切面(AOP)

OPP 命名法问题:object->function($param)

安卓手机里以opp后缀的是啥文件

三层架构的OPP实现的演示例子