当前位置: 首页 > news >正文

网站开发 华景新城做解析视频网站怎么赚钱

网站开发 华景新城,做解析视频网站怎么赚钱,wordpress的数据库有多大,建设网站目的及功能定位是什么标题 时钟系统说明时钟树Clock Provider时钟通用数据结构clock_device 的注册clock_provider DTS配置和注册clock consumer时钟系统总结 时钟系统说明 时钟就是 SoC 中的脉搏#xff0c;由它来控制各个部件按各自的节奏跳动。比如#xff0c;CPU主频设置#xff0c;串口的波… 标题 时钟系统说明时钟树Clock Provider时钟通用数据结构clock_device 的注册clock_provider DTS配置和注册clock consumer时钟系统总结 时钟系统说明 时钟就是 SoC 中的脉搏由它来控制各个部件按各自的节奏跳动。比如CPU主频设置串口的波特率设置I2S的采样率设置I2C的速率设置等等。这些不同的 clock 设置都需要从某个或某几个时钟源头而来最终开枝散叶形成一棵时钟树。 Linux的时钟子系统由CCFcommon clock framework 框架管理CCF向上给其他使用时钟的 IP 提供了通用的时钟接口向下给驱动开发者提供硬件操作的接口。 这个也是一个consumer、framework、provider的模式。 Provider 是时钟的模块的具体实现者系统开机时需要通过驱动的时钟框架向系统注册不同的时钟。Provider其他需要时钟的模块通过通用接口获取使能设置时钟。 Framework 是内核提供的一套通用时钟实现框架包含了注册和使用的通用接口。 Consumer 是时钟模块的使用者比如上面提到的 I2C 模块Uart 模块的等等。 电源管理的两大主要方面就是时钟和电压 时钟树 在SoC上的模块很多为了适应不同模块的时钟要求会形成一课时钟树如下所示 根节点一般是 Oscillator有源振荡器或者 Crystal无源振荡器表示从芯片外部输入的基准时钟 中间节点有很多种包括 PLL锁相环用于提升频率的Divider分频器用于降频的Mux从多个clock path中选择一个Gate只能被控制ON/OFF的。 根据不同时钟的特点clock framework 将 clock 分为 **Fixed rate、gate、Divider、Mux、Fixed factor、composite **六类这六类的含义如下 Fixed rate clock 固定频率时钟提供恒定的时钟信号适用于需要固定频率的硬件如PWM脉宽调制或定时器。Gated clock 门控时钟只可以被开启或关闭适用于可以被动态开启或者关闭的硬件以节约电源Divider clock 分频时钟可以将输入的时钟信号分频产生一个较低频率的时钟信号适用于需要降低时钟频率适应设备需要的设备Muxed clock: 复用时钟时钟信号可以选择不同的时钟源Fixed factor clock 固定系数时钟可以将输入时钟信号乘以一个固定的系数产生一个更高或者更低的时钟信号Composite clock组合时钟可以由多个时钟实体组成每个时钟实体都有特定的功能适用于复杂时钟控制策略的硬件比如复杂时钟路径和时钟管理 Linux 下 cat /sys/kernel/debug/clk/clk_summary 可以查看当前 Soc 的时钟树 Clock Provider 时钟通用数据结构 Linux 内核将上面六类设备特点抽象出来用 struct clk_hw 表示 struct clk_hw {//指向CCF模块中对应 clock device 实例struct clk_core *core;//clk是访问clk_core的实例 每当consumer通过clk_get对CCF中的clock device也就是clk_core发起访问的时候都需要获取一个句柄也就是clkstruct clk *clk;//clock provider driver初始化时的数据数据被用来初始化clk_hw对应的clk_core数据结构。const struct clk_init_data *init; };struct clk_init_data {//该clock设备的名字const char *name;//clock provider driver 进行的具体的 HW 操作const struct clk_ops *ops;//描述该clk_hw的拓扑结构const char * const *parent_names;const struct clk_parent_data *parent_data;const struct clk_hw **parent_hws;u8 num_parents;unsigned long flags; };以 Fixed rate clock 和 gate clock 为例它就包含一个 struct clk_hw 结构作为核心 struct clk_fixed_rate {// 包含的 clk_hw 结构struct clk_hw hw;unsigned long fixed_rate;unsigned long fixed_accuracy;u8 flags; };struct clk_gate {struct clk_hw hw;void __iomem *reg;u8 bit_idx;u8 flags;spinlock_t *lock; };由此可以知道 每次注册进入内核的 clock device 设备都会包含一个 struct clk_hw 结构strutc clk_hw 包含一个重要的结构体成员 const struct clk_init_data *init里面包含了注册进入内核的时钟的具体操作方法 struct clk_init_data 包含一个重要成员 clk_ops里面就是时钟设备的具体操作方法函数 struct clk_ops {int (*prepare)(struct clk_hw *hw);void (*unprepare)(struct clk_hw *hw);int (*is_prepared)(struct clk_hw *hw);void (*unprepare_unused)(struct clk_hw *hw);int (*enable)(struct clk_hw *hw);void (*disable)(struct clk_hw *hw);int (*is_enabled)(struct clk_hw *hw);void (*disable_unused)(struct clk_hw *hw);unsigned long (*recalc_rate)(struct clk_hw *hw,unsigned long parent_rate);long (*round_rate)(struct clk_hw *hw, unsigned long rate,unsigned long *parent_rate);int (*determine_rate)(struct clk_hw *hw,struct clk_rate_request *req);int (*set_parent)(struct clk_hw *hw, u8 index);u8 (*get_parent)(struct clk_hw *hw);int (*set_rate)(struct clk_hw *hw, unsigned long rate,unsigned long parent_rate);int (*set_rate_and_parent)(struct clk_hw *hw,unsigned long rate,unsigned long parent_rate, u8 index);unsigned long (*recalc_accuracy)(struct clk_hw *hw,unsigned long parent_accuracy);int (*get_phase)(struct clk_hw *hw);int (*set_phase)(struct clk_hw *hw, int degrees);void (*init)(struct clk_hw *hw);int (*debug_init)(struct clk_hw *hw, struct dentry *dentry); };struct clk_init_data {const char *name;const struct clk_ops *ops;const char * const *parent_names;u8 num_parents;unsigned long flags; };clock_device 的注册 clock_provider 注册的流程如下图 这里的注册是指将不同的 clock_device 注册到内核的 CCF 框架中具体时钟驱动的匹配和注册在下面讲介绍: 首先 Linux 内核会读取设备树中定义的不同的 clock_device 节点匹配到不同的 clock_init 函数在 clock_init 函数中根据设备树的配置注册不同类型的 clock_device到 CCF 中 不同的 clock_device 都会提供 register 函数用于注册举例如下 // include/linux/clock-provider.h struct clk *clk_register_gate(struct device *dev, const char *name,const char *parent_name, unsigned long flags,void __iomem *reg, u8 bit_idx,u8 clk_gate_flags, spinlock_t *lock);struct clk *clk_register_divider(struct device *dev, const char *name,const char *parent_name, unsigned long flags,void __iomem *reg, u8 shift, u8 width,u8 clk_divider_flags, spinlock_t *lock);struct clk *clk_register_divider_table(struct device *dev, const char *name,const char *parent_name, unsigned long flags,void __iomem *reg, u8 shift, u8 width,u8 clk_divider_flags, const struct clk_div_table *table,spinlock_t *lock); ... clk_register_mux(...); clk_register_mux_table(...); clk_register_fixed_factor(...); clk_register_composite(...);这些注册函数最终都会通过函数 clk_register 注册到 Common Clock Framework 中返回为 struct clk 指针。如下所示 在内核的drivers/clk目录下可以看到各个芯片厂商对各自芯片 clock 驱动的实现 clock_provider DTS配置和注册 在设备数中需要首先定义 clock_provider 的特性节点以 rk3399 为例下面的 cruclock reset unit 的配置如下 cru: clock-controllerff760000 {compatible rockchip,rk3399-cru;reg 0x0 0xff760000 0x0 0x1000;rockchip,grf grf;#clock-cells 1;#reset-cells 1;assigned-clocks cru PLL_GPLL, cru PLL_CPLL,cru PLL_NPLL,cru ACLK_PERIHP, cru HCLK_PERIHP,cru PCLK_PERIHP,cru ACLK_PERILP0, cru HCLK_PERILP0,cru PCLK_PERILP0, cru ACLK_CCI,cru HCLK_PERILP1, cru PCLK_PERILP1;assigned-clock-rates 594000000, 800000000,1000000000,150000000, 75000000,37500000,100000000, 100000000,50000000, 600000000,100000000, 50000000; };不同属性的的含义如下 属性含义compatible驱动的匹配名称内核通过字段匹配到不同的初始化函数clock-output-names输出时钟的名字当consumer 使用此时钟时使用该属性的值clock-frequency输出时钟的频率clock-cells输出的时钟的路数当#clock-cells为0时代表仅输出1路时钟若大于等于1则代表输出多路时钟Clock consumers通过编号索引使用。assigned-clocks表示该设备需要使用时钟信号这个属性的值是一个整数数组每一个元素对应一个时钟信号assigned-clock-rates和 assigned-clocks 成对使用表述输入时钟的频率 在 Linux 内核代码中还需要声明相匹配的时钟驱动这样在初始化阶段内核就可以自动匹配 DTS 中的 compatible 字段向系统注册时钟设备 CLK_OF_DECLARE 宏用于声明与设备树DeviceTree绑定的时钟控制器驱动 CLK_OF_DECLARE 宏的定义如下 #define CLK_OF_DECLARE(name, compat, fn) \OF_DECLARE_1(clk_of_match, name, compat, fn)//name时钟提供者的名称通常是一个结构体的实例。 //compat与设备树中兼容性字段匹配的字符串用于识别时钟控制器。 //fn一个函数指针指向用于初始化时钟控制器的函数。 //当内核解析设备树时它会查找与compat参数匹配的节点并调用fn参数指定的函数来初始化时钟控制器。这样内核就可以通过设备树来配置和管理设备的时钟继续跟踪 CLK_OF_DECLARE 的代码可以看到 #define CLK_OF_DECLARE(name, compat, fn) OF_DECLARE_1(clk, name, compat, fn)#define OF_DECLARE_1(table, name, compat, fn) \_OF_DECLARE(table, name, compat, fn, of_init_fn_1)#define _OF_DECLARE(table, name, compat, fn, fn_type) \static const struct of_device_id __of_table_##name \__used __section(__##table##_of_table) \ { .compatible compat, \.data (fn (fn_type)NULL) ? fn : fn }// 如果将 fn 传入参数 hi6220_clk_media那么展开后可以看到下面的一个实例 static const struct of_device_id __of_table_hi6220_clk_media__used __section(__clk_of_table) {.compatible compat;.data fn; // check fn type __init 函数} 本质上定义了 struct of_device_id 结构使用 compatible 字段进行匹配 所以 clock 驱动编写的一般步骤是 实现 struct clk_ops 相关成员函数定义分配 struct clk_onecell_data 结构体初始化相关数据定义分配 struct clk_init_data 结构体初始化相关数据调用 clk_register 将时钟注册进框架调用 clk_register_clkdev 注册时钟设备调用 of_clk_add_provider将 clk provider 存放到 of_clk_provider 链表中管理调用 CLK_OF_DECLARE 声明驱动 其中的第二步struct clk_onecell_data 是在 clk-provider.h 中定义结构如下 struct clk_onecell_data {struct clk **clks;unsigned int clk_num; };一般用于保存 clk_register 函数的返回值 struct clk 结构并将其作为私有数据参数通过 of_clk_add_provider 注册到 of_clk_provider 链表中 struct clk_onecell_data *clk_data;clk_data kzalloc(sizeof(struct clk_onecell_data), GFP_KERNEL);......clk_data-clks kzalloc(qty * sizeof(struct clk *), GFP_KERNEL);.....clk_data-clks[i] clk_register_gate(NULL, clk_name,clk_parent, clkflags,reg_idx, reg_bit,flags,clk_lock);clk_data-clk_num qty;of_clk_add_provider(node, of_clk_src_onecell_get, clk_data);clock consumer Clock consumers意为时钟使用者通常是CPU核心部件或者其他外设。 下面是一个 clock consumer 的配置 i2c8: i2cff3e0000 {compatible rockchip,rk3399-i2c;reg 0x0 0xff3e0000 0x0 0x1000;assigned-clocks pmucru SCLK_I2C8_PMU;assigned-clock-rates 200000000;clocks pmucru SCLK_I2C8_PMU, pmucru PCLK_I2C8_PMU;clock-names i2c, pclk;interrupts GIC_SPI 58 IRQ_TYPE_LEVEL_HIGH 0;pinctrl-names default;pinctrl-0 i2c8_xfer;#address-cells 1;#size-cells 0;status disabled;};clocks 属性它代表了设备的时钟源通常以 phandle specifier 组合进行引用比如在本例中使用的时钟是pmcru 中的 SCLK_I2C8_PMU 和 PCLK_I2C8_PMU 作为时钟源 clock-names这代表了Clock consumers中使用的时钟名字方便设备驱动代码进行相应的时钟解析 比如使用下面的代码进行解析 mdev-aclk devm_clk_get(dev, aclk);if (IS_ERR(mdev-aclk)) {DRM_ERROR(Get engine clk failed.\n);err PTR_ERR(mdev-aclk);mdev-aclk NULL;goto err_cleanup;}clk_prepare_enable(mdev-aclk);clock comsumer 的架构如下所示 主要就是获取和操作 clk即通过 clock 名称获取 struct clk 指针的过程由 clk_get、devm_clk_get、clk_get_sys、of_clk_get、of_clk_get_by_name、of_clk_get_from_provider 等接口负责实现 //启动clock前的准备工作/停止clock后的善后工作。可能会睡眠。 int clk_prepare(struct clk *clk) void clk_unprepare(struct clk *clk)//启动/停止clock。不会睡眠。 static inline int clk_enable(struct clk *clk) static inline void clk_disable(struct clk *clk)//clock频率的获取和设置 static inline unsigned long clk_get_rate(struct clk *clk) static inline int clk_set_rate(struct clk *clk, unsigned long rate) static inline long clk_round_rate(struct clk *clk, unsigned long rate)//获取/选择clock的parent clock static inline int clk_set_parent(struct clk *clk, struct clk *parent) static inline struct clk *clk_get_parent(struct clk *clk)//将clk_prepare和clk_enable组合起来一起调用。将clk_disable和clk_unprepare组合起来一起调用 static inline int clk_prepare_enable(struct clk *clk) static inline void clk_disable_unprepare(struct clk *clk)注意 clk_prepare() 和 clk_enable() 是两个不同的函数 clk_prepare() 函数的作用是准备时钟它执行时钟的初始化操作但并不立即启用时钟。这个函数的主要目的是为了确保时钟在启用之前所有的准备工作都已经完成比如分配必要的资源、设置初始参数等。调用clk_prepare后时钟处于“已准备”状态但还没有开始运行。 clk_enable函数的作用是启用时钟它使得时钟开始运行并提供时钟信号给相关的硬件。在调用clk_enable之前必须先调用clk_prepare来确保时钟已经准备好。一旦时钟被启用它就可以被硬件设备使用。 这里分析一下 clk_get 函数的实现过程 struct clk *clk_get(struct device *dev, const char *con_id) {const char *dev_id dev ? dev_name(dev) : NULL;struct clk *clk;if (dev) {// 通过扫描所有 clock-names 中的值和传入的 name 比较如果相同获得它的 index即 clock-names 中的第几个调用 of_clk_get取得 clock指针。clk __of_clk_get_by_name(dev-of_node, dev_id, con_id);if (!IS_ERR(clk) || PTR_ERR(clk) -EPROBE_DEFER)return clk;}return clk_get_sys(dev_id, con_id); }时钟系统总结 Linux 的时钟框架的简要关系可以用下图来说明 clock provider 使用 clk_hw 结构向 CCF 框架注册一个时钟设备返回一个 struct clk 结构其中 clk_hw 结构中 包含了 struct clk_inid_data 结构 struct clk_init_data 结构包含对时钟操作的具体函数集合 struct clk_ops为了简化操作CCF 将 clock 设备抽象为六中不同的类型并且做了相应的接口封装比如对于 gate 类型的设备直接使用 clk_register_gate 等类型的函数就可以进行注册CCF 框架会为每个注册的 clock_device 都分配一个 struct clk_core 结构其中包含了操作函数的结构体 struct clk_ops 结构本质就是关联到 init_data 中的 clk_opsconsumer 通过 clk_get 等函数 获取的 struct clk 结构其中包含了重要结构就是 struct clk_core通过操作里面的 struct clk_ops 就可以关联到注册进入 CCF 框架的 clk_ops 结构实现对时钟硬件设备操作的目的 文件中的关键代码路径 include/linux/clk.h include/linux/clk.c include/linux/clk-provider.hdriver/clk/clk-gate.c driver/clk/clk-mux.c driver/clk/clk-divider.c参考网址 Linux kernel中的CPU时钟管理
http://www.zqtcl.cn/news/588381/

相关文章:

  • 网站轮播图怎么设计河南省住房城乡建设厅网站首页
  • o2o商城网站建设wordpress后台密码忘记了怎么办
  • 网站排版策划公司官网网站建设想法
  • 泉州网站建设报价建网站找哪家公司
  • 国外网站建设推广iapp网站怎么做软件
  • 网站的设计步骤做网站的虚拟机怎么用
  • 游戏的网站做普通网站多少钱
  • 单位门户网站建设苏州吴中区做网站公司
  • 新网站内部优化怎么做家电网站建设
  • 怎么看网站源码用什么做的wordpress 六亩填
  • 网站建设实习报告范文闵行区邮编
  • h5网站模板免费下载怎样制作专业简历
  • php网站语言切换功能如何做263邮箱入口
  • 电商网站及企业微信订烟专门做红酒的网站
  • 大庆商城网站建设微网站建设找哪家
  • 渝快办官网seo管理平台
  • 网站建设辶金手指排名十二厦门建设局
  • 网站反链接什么seo推广优化多少钱
  • 建设工程公司采购的网站找不到网站后台怎么办
  • 江门网站seo推广湖南省建设银行网站官网
  • 网站底部关键词指向网站打开速度慢跟什么有关系
  • 网站右侧广告合肥高端网站设计
  • 漯河市郾城区网站建设wordpress文件管理
  • 网站栅格大连做网站的
  • 珠海企业网站建设报价鄂州网吧什么时候恢复营业
  • 手机制作钓鱼网站id转换为wordpress
  • 手机网站 好处信用中国 网站有那个部门支持建设
  • 模板免费网站自己如何做网站优化
  • 自适应网站做mip改造淘宝上买衣服的网站
  • 射阳做企业网站哪家好利用新冠消灭老年人