Linux内核4.14版本——ccf时钟子系统(6)——DTS相关的API

目录

1. of_clk_add_provider

2. of_clk_get_from_provider

2.1 __of_clk_get_hw_from_provider

2.2 __clk_create_clk

3. of_clk_set_defaults

3.1 __set_clk_parents

3.2 __set_clk_rates


      再回到第2章DTS相关的介绍,clock driver使用一个DTS node描述一个clock provider,而clock consumer则会使用类似“clocks = <&clock  32>, <&clock 45>;”的形式引用,clock framework会自行把这些抽象的数字转换成实际的struct clk结构,怎么做的呢?肯定离不开clock provider的帮助。

1. of_clk_add_provider

       第4章描述的regitser接口,负责把clocks抽象为一个一个的struct clock,与此同时,clock provider需要把这些struct clk结构保存起来,并调用clock framework的接口,将这些对应信息告知framework的OF模块,这样才可以帮助将clock consumer的DTS描述转换为struct clk结构。该接口如下:

/*** of_clk_add_provider() - Register a clock provider for a node* @np: Device node pointer associated with clock provider* @clk_src_get: callback for decoding clock* @data: context pointer for @clk_src_get callback.*/
int of_clk_add_provider(struct device_node *np,struct clk *(*clk_src_get)(struct of_phandle_args *clkspec,void *data),void *data)
{struct of_clk_provider *cp;int ret;cp = kzalloc(sizeof(*cp), GFP_KERNEL);if (!cp)return -ENOMEM;cp->node = of_node_get(np);cp->data = data;cp->get = clk_src_get;mutex_lock(&of_clk_mutex);list_add(&cp->link, &of_clk_providers);mutex_unlock(&of_clk_mutex);pr_debug("Added clock from %pOF\n", np);ret = of_clk_set_defaults(np, true);if (ret < 0)of_clk_del_provider(np);return ret;
}

       np,device_node指针,clock provider在和自己的DTS匹配时获得;
       clk_src_get,获取struct clk指针的回调函数,由clock provider根据实际的逻辑实现,参数说明如下:
       args,struct of_phandle_args类型的指针,由DTS在解析参数时传递。例如上面的“clocks = <&clock  32>, <&clock 45>;”,32、45就是通过这个指针传进来的;
       data,保存struct clk结构的指针,通常是一个数组,具体由provider决定。
       data,和回调函数中的data意义相同,只是这里由provider提供,get时由clock framework core传递给回调函数。

      把该provider加到全局链表of_clk_providers保存起来,方面后面其他模块使用。

       对于常用的one cell clock provider,clock framework core提供一个默认的会调用函数,如下:

struct clk_onecell_data {struct clk **clks;unsigned int clk_num;
};
struct clk *of_clk_src_onecell_get(struct of_phandle_args *clkspec, void *data);

       其中data指针为struct clk_onecell_data结构,该结构提供了clk指针和clk_num的对应,clock provider在regitser clocks时,同时维护一个clk和num对应的数组,并调用of_clk_add_provider接口告知clock framework core即可。

struct clk *of_clk_src_onecell_get(struct of_phandle_args *clkspec, void *data)
{struct clk_onecell_data *clk_data = data;unsigned int idx = clkspec->args[0];if (idx >= clk_data->clk_num) {pr_err("%s: invalid clock index %u\n", __func__, idx);return ERR_PTR(-EINVAL);}return clk_data->clks[idx];
}

2. of_clk_get_from_provider

struct clk *__of_clk_get_from_provider(struct of_phandle_args *clkspec,const char *dev_id, const char *con_id)
{struct of_clk_provider *provider;struct clk *clk = ERR_PTR(-EPROBE_DEFER);struct clk_hw *hw;if (!clkspec)return ERR_PTR(-EINVAL);/* Check if we have such a provider in our array */mutex_lock(&of_clk_mutex);list_for_each_entry(provider, &of_clk_providers, link) {if (provider->node == clkspec->np) {hw = __of_clk_get_hw_from_provider(provider, clkspec);clk = __clk_create_clk(hw, dev_id, con_id);}if (!IS_ERR(clk)) {if (!__clk_get(clk)) {__clk_free_clk(clk);clk = ERR_PTR(-ENOENT);}break;}}mutex_unlock(&of_clk_mutex);return clk;
}/*** of_clk_get_from_provider() - Lookup a clock from a clock provider* @clkspec: pointer to a clock specifier data structure** This function looks up a struct clk from the registered list of clock* providers, an input is a clock specifier data structure as returned* from the of_parse_phandle_with_args() function call.*/
struct clk *of_clk_get_from_provider(struct of_phandle_args *clkspec)
{return __of_clk_get_from_provider(clkspec, NULL, __func__);
}

       最终调到__of_clk_get_hw_from_provider和__clk_create_clk函数。

2.1 __of_clk_get_hw_from_provider

static struct clk_hw *
__of_clk_get_hw_from_provider(struct of_clk_provider *provider,struct of_phandle_args *clkspec)
{struct clk *clk;if (provider->get_hw)return provider->get_hw(clkspec, provider->data);//实际调用的是它clk = provider->get(clkspec, provider->data);if (IS_ERR(clk))return ERR_CAST(clk);return __clk_get_hw(clk);
}

        最终调用的是provider->get(clkspec, provider->data);这个函数赋值实际上是在of_clk_add_provider函数中,即clk_src_get,也就是默认提供的of_clk_src_onecell_get。注意of_clk_src_onecell_get函数返回的是一个struct clk结构体,但是最终__of_clk_get_hw_from_provider返回的是strutc clk_hw结构体。

2.2 __clk_create_clk

struct clk *__clk_create_clk(struct clk_hw *hw, const char *dev_id,const char *con_id)
{struct clk *clk;/* This is to allow this function to be chained to others */if (IS_ERR_OR_NULL(hw))return ERR_CAST(hw);clk = kzalloc(sizeof(*clk), GFP_KERNEL);if (!clk)return ERR_PTR(-ENOMEM);clk->core = hw->core;clk->dev_id = dev_id;clk->con_id = kstrdup_const(con_id, GFP_KERNEL);clk->max_rate = ULONG_MAX;clk_prepare_lock();hlist_add_head(&clk->clks_node, &hw->core->clks);clk_prepare_unlock();return clk;
}

     重新生成一个struct clk结构体。

3. of_clk_set_defaults

int of_clk_set_defaults(struct device_node *node, bool clk_supplier)
{int rc;if (!node)return 0;rc = __set_clk_parents(node, clk_supplier);if (rc < 0)return rc;return __set_clk_rates(node, clk_supplier);
}

       of_clk_set_defaults是解析dts里面时钟的配置的,一般是在上电启动过程中,根据DTS来进行时钟的初始化操作。

[    0.000000]  dump_backtrace+0x0/0x180                                                                                            
[    0.000000]  show_stack+0x28/0x34                                                                                                
[    0.000000]  dump_stack+0xa0/0xc4                                                                                                
[    0.000000]  of_clk_set_defaults+0x5c/0x430                                                                                      
[    0.000000]  of_clk_add_provider+0xa8/0x10c                                                                                      
[    0.000000]  _of_fixed_clk_setup+0xc0/0xf4                                                                                       
[    0.000000]  of_fixed_clk_setup+0x24/0x30                                                                                        
[    0.000000]  of_clk_init+0x1b8/0x238                                                                                             
[    0.000000]  time_init+0x1c/0x4c                                                                                                 
[    0.000000]  start_kernel+0x264/0x384     

       of_clk_set_defaults也会在设备驱动匹配上时候调用。

[   22.023909] Call trace:                                                                                                          
[   22.026378]  dump_backtrace+0x0/0x180                                                                                            
[   22.030097]  show_stack+0x28/0x34                                                                                                
[   22.033440]  dump_stack+0xa0/0xc4                                                                                                
[   22.036785]  of_clk_set_defaults+0x5c/0x430                                                                                      
[   22.041009]  platform_drv_probe+0x30/0xcc                                                                                        
[   22.045042]  driver_probe_device+0x264/0x454                                                                                     
[   22.049326]  __driver_attach+0x118/0x130                                                                                         
[   22.053298]  bus_for_each_dev+0x7c/0xc0                                                                                          
[   22.057142]  driver_attach+0x34/0x40                                                                                             
[   22.060734]  bus_add_driver+0x1d4/0x27c                                                                                          
[   22.064578]  driver_register+0x80/0x120                                                                                          
[   22.068422]  __platform_driver_register+0x58/0x6c                                                                                
[   22.073177]  cve_module_init+0x18/0x1000 [ts_cve]                                                                                
[   22.077903]  do_one_initcall+0x48/0x130                                                                                          
[   22.081749]  do_init_module+0x64/0x28c                                                                                           
[   22.085531]  load_module+0x2270/0x2834                                                                                           
[   22.089312]  SyS_finit_module+0xc8/0xfc                                                                                          
[   22.093156]  el0_svc_naked+0x34/0x38   

       of_clk_set_defaults函数用来解析dts中assigned-{clocks/clock-parents/clock-rates}参数的,我们以下面的例子分析一下。

&spi0 {clocks = <&ts_clk TS_CLK_TX5112_SPI_SSICLK>, <&ts_clk TS_CLK_TX5112_SPI_PCLK>;clock-names = "ref_clk", "pclk";assigned-clocks = <&ts_clk TS_CLK_TX5112_SPI_SSICLK>;assigned-clock-rates = <62000000>;assigned-clock-parents = <&ts_clk TS_CLK_TX5112_PLL1>;
};

3.1 __set_clk_parents

static int __set_clk_parents(struct device_node *node, bool clk_supplier)
{struct of_phandle_args clkspec;int index, rc, num_parents;struct clk *clk, *pclk;num_parents = of_count_phandle_with_args(node, "assigned-clock-parents","#clock-cells");if (num_parents == -EINVAL)pr_err("clk: invalid value of clock-parents property at %pOF\n",node);pr_debug("num_parents: %d\n", num_parents);for (index = 0; index < num_parents; index++) {rc = of_parse_phandle_with_args(node, "assigned-clock-parents","#clock-cells",	index, &clkspec);if (rc < 0) {/* skip empty (null) phandles */if (rc == -ENOENT)continue;elsereturn rc;}if (clkspec.np == node && !clk_supplier)return 0;pclk = of_clk_get_from_provider(&clkspec);if (IS_ERR(pclk)) {if (PTR_ERR(pclk) != -EPROBE_DEFER)pr_warn("clk: couldn't get parent clock %d for %pOF\n",index, node);return PTR_ERR(pclk);}rc = of_parse_phandle_with_args(node, "assigned-clocks","#clock-cells", index, &clkspec);if (rc < 0)goto err;if (clkspec.np == node && !clk_supplier) {rc = 0;goto err;}clk = of_clk_get_from_provider(&clkspec);pr_debug("%s node_name:%s clk_name:%s pclk_name:%s\n", __func__, node->name, __clk_get_name(clk), __clk_get_name(pclk));if (IS_ERR(clk)) {if (PTR_ERR(clk) != -EPROBE_DEFER)pr_warn("clk: couldn't get assigned clock %d for %pOF\n",index, node);rc = PTR_ERR(clk);goto err;}rc = clk_set_parent(clk, pclk);if (rc < 0)pr_err("clk: failed to reparent %s to %s: %d\n",__clk_get_name(clk), __clk_get_name(pclk), rc);clk_put(clk);clk_put(pclk);}return 0;
err:clk_put(pclk);return rc;
}

       (1)先用of_count_phandle_with_args计算该dts中parent的个数。
       (2)根据parent的个数,对每个parent进行如下操作。
                a)  得到assigned-clock-parents该父时钟相关的参数结构体clkspec
                b)  通过of_clk_get_from_provider得到该父时钟的struct clk结构体。
                c)得到assigned-clock指定的时钟相关的参数结构体clkspec
                d)通过of_clk_get_from_provider得到该时钟的struct clk结构体。
                e)设置clk_set_parent子父时钟关系。

3.2 __set_clk_rates

static int __set_clk_rates(struct device_node *node, bool clk_supplier)
{struct of_phandle_args clkspec;struct property	*prop;const __be32 *cur;int rc, index = 0;struct clk *clk;u32 rate;of_property_for_each_u32(node, "assigned-clock-rates", prop, cur, rate) {if (rate) {rc = of_parse_phandle_with_args(node, "assigned-clocks","#clock-cells",	index, &clkspec);if (rc < 0) {/* skip empty (null) phandles */if (rc == -ENOENT)continue;elsereturn rc;}if (clkspec.np == node && !clk_supplier)return 0;clk = of_clk_get_from_provider(&clkspec);pr_debug("%s node_name:%s clk_name:%s rate:%u\n", __func__, node->name, __clk_get_name(clk), rate);if (IS_ERR(clk)) {if (PTR_ERR(clk) != -EPROBE_DEFER)pr_warn("clk: couldn't get clock %d for %pOF\n",index, node);return PTR_ERR(clk);}rc = clk_set_rate(clk, rate);if (rc < 0)pr_err("clk: couldn't set %s clk rate to %u (%d), current rate: %lu\n",__clk_get_name(clk), rate, rc,clk_get_rate(clk));clk_put(clk);}index++;}return 0;
}

       (1)遍历assigned-clock-rates里面的结构体变量,相当于for循环。
       (2)对每个rate进行如下操作。
                a)得到assigned-clock指定的时钟相关的参数结构体clkspec
                b)通过of_clk_get_from_provider得到该时钟的struct clk结构体。
                c)设置clk_set_rate时钟频率。

3.3 调用关系

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/pingmian/62739.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

2024年度桌面便签软件电脑版推荐

随着2024年的尾声渐近&#xff0c;这一年中涌现出了许多优秀的软件&#xff0c;其中便签软件因其便捷性和高效性成为了备受欢迎的工具。这类软件无论是在工作还是日常生活中&#xff0c;都极大地提升了我们的效率和生活质量。 在众多桌面便签中&#xff0c;敬业签是一款值得推…

WPS for Mac免登录使用工具栏

一、mac下载国际版https://www.wps.com 下载下来是在线安装包&#xff0c;对了&#xff0c;不再需要汉化&#xff01;&#xff01;&#xff01; 二、干掉登录 进入目录/Applications/wpsoffice.app/Contents/Frameworks/office6&#xff08;访达、应用程序、wpsoffice.app右…

【计算机网络】实验3:集线器和交换器的区别及交换器的自学习算法

实验 3&#xff1a;集线器和交换器的区别及交换器的自学习算法 一、 实验目的 加深对集线器和交换器的区别的理解。 了解交换器的自学习算法。 二、 实验环境 • Cisco Packet Tracer 模拟器 三、 实验内容 1、熟悉集线器和交换器的区别 (1) 第一步&#xff1a;构建网络…

【技巧】Mac上如何显示键盘和鼠标操作

在制作视频教程时&#xff0c;将键盘和鼠标的操作在屏幕上显示出来&#xff0c;会帮助观众更容易地理解。 推荐Mac上两款开源的小软件。 1. KeyCastr 这款工具从2009年至今一直在更新中。 https://github.com/keycastr/keycastr 安装的话&#xff0c;可以从Github上下载最…

Docker:在 ubuntu 系统上生成和加载 Docker 镜像

本文将介绍在 ubuntu系统上进行 Docker 镜像的生成和加载方法和代码。 文章目录 一、下载和安装 docker二、加载 docker 文件三、保存你的镜像四、将镜像上传到云端并通过连接下载和加载 Docker 镜像五、Docker 容器和本地的文件交互5.1 从容器复制文件到本地宿主机5.1.1 单个文…

PHP爬虫性能优化:从多线程到连接池的实现

背景介绍 随着网络数据的爆炸式增长&#xff0c;爬虫技术成为数据获取的重要工具。从市场调研到用户行为分析&#xff0c;爬虫的应用无处不在。然而&#xff0c;在实际应用中&#xff0c;我们常常遇到爬虫性能不足的问题&#xff1a;单线程处理效率低下、请求超时、数据采集量…

《现代网络技术》读书笔记:网络虚拟化

本文部分内容来源于《现代网络技术&#xff1a;SDN,NFV,QoE、物联网和云计算&#xff1a;SDN,NFV,QoE,IoT,andcloud》 虚拟局域网 图9-1显示了一个比较常见的层次化局域网场景&#xff0c;在这个例子中&#xff0c;局域网中的设备分为四个部分&#xff0c;每个部分都通过以太网…

在c#控制台中使用Raylib-cs库,绘制控制小球和插入音频(附带c++中小球的控制代码)

下载网址 GitHub - chrisdill/raylib-cs: C# bindings for raylib, a simple and easy-to-use library to learn videogames programming 克隆库 克隆GitHub仓库-CSDN博客 1 .制作dll 点击 生成之后就会多出这些东西 2.在项目中添加dll 然后就导进来了 测试一下用例代码 …

「Mac畅玩鸿蒙与硬件40」UI互动应用篇17 - 照片墙布局

本篇将带你实现一个简单的照片墙布局应用&#xff0c;通过展示多张图片组成照片墙效果&#xff0c;用户可以点击图片查看其状态变化。 关键词 UI互动应用照片墙布局Grid 布局动态图片加载用户交互 一、功能说明 照片墙布局应用的特点&#xff1a; 动态加载多张图片组成网格布…

数字图像处理(12):灰度二值化

灰度像素&#xff1a;在 RGB 颜色模型下&#xff0c;图像中每个像素颜色的 R、G、B 三种基色的分量值相等的像素。由灰度像素组成的灰度图像只能表现256中颜色&#xff08;或亮度&#xff09;&#xff0c;通常把灰度图像中像素的亮度称为灰度值。灰度化处理&#xff1a;是指把彩…

华为新手机和支付宝碰一下 带来更便捷支付体验

支付正在变的更简单。 11月26日&#xff0c;华为新品发布会引起众多关注。发布会上&#xff0c;华为常务董事余承东专门提到&#xff0c;华为Mate 70和Mate X6折叠屏手机的“独门支付秘技”——“碰一下”&#xff0c;并且表示经过华为和支付宝的共同优化&#xff0c;使用“碰…

Redis开发05:使用stackexchange.redis库对redis进行增删改查

一、安装第三方库 二、官网 StackExchange.Redis |通用型 redis 客户端 三、连接示例 private static string redisConnectionString "localhost:6379,passwordyourpassword,defaultDatabase0,allowAdmintrue,asyncTimeout10000";private static string redisConn…

Electron + vue3 打包之后不能跳转路由

路由不跳转问题原因&#xff1a; 是因为electron需要将vue-router的mode调整为hash模式(两种写法) export default new Router({mode: hash, //这里history修改为hashscrollBehavior: () > ({y: 0}),routes: constantRouterMap, }) export default new createRouter({his…

React第十节组件之间传值之context

1、Context 使用creatContext() 和 useContext() Hook 实现多层级传值 概述&#xff1a; 在我们想要每个层级都需要某一属性&#xff0c;或者祖孙之间需要传值时&#xff0c;我们可以使用 props 一层一层的向下传递&#xff0c;或者我们使用更便捷的方案&#xff0c;用 creatC…

基于群晖搭建个人图书架-TaleBook based on Docker

前言 在群晖Container Manager中部署失败&#xff0c;转通过ssh部署。 一、准备工作 名称备注群晖SSH“终端机和SNMP”中启用SSH软件secureCRT等docker-compose.ymlGithub下载并修改 二、过程 2.1 创建本地文件夹 本地路径为&#xff1a; /docker/Calibre/data 2.2 下载d…

【JavaEE】JavaEE、web 开发、框架(Spring) 、Maven

文章目录 一、JavaEE 发展历程二、什么是 web 开发1、什么是 web 开发&#xff1f;2、web 网站的工作流程 三、框架1、什么是框架&#xff1f;2、为什么要学框架&#xff1f;3、框架的优点&#xff08;Spring Boot VS Servlet&#xff09; 四、Maven 一、JavaEE 发展历程 Java…

vue3项目中使用星火API

在node环境epxress中使用讯飞ai接口进行二次封装&#xff0c;通过ai对话回复提取&#xff0c;获得ai提取的文章摘要 本文章只是简单使用&#xff0c;更复杂功能比如调用星火API制作对话机器人可以查看文档&#xff0c;对于初次使用星火AI接口或许有帮助 讯飞星火大模型API-大模…

基于centos7.9容器编排Jumpserver堡垒机

Jum 基础环境容器化部署MySQL容器化部署Redis容器化部署Nginx容器化部署Koko容器化部署Guacamole容器化部署Core编排compose文件 基础环境 基于centos7.9容器化部署jumpserver tar -xf JumpServer.tar.gz导入centos7.9 docker镜像 docker load -i images/centos_7.9.2009.ta…

5G学习笔记之PRACH

即使是阴天&#xff0c;也要记得出门晒太阳哦 目录 1. 概述 2. PRACH Preamble 3. PRACH Preamble 类型 3.1 长前导码 3.2 短前导码 3.3 前导码格式与小区覆盖 4. PRACH时频资源 4.1 小区所有可用PRACH资源 4.2 SSB和RACH的关系 4.3 PRACH时频资源配置 1. 概述 随机接入…

14 - Java 面向对象(中级)

包&#xff08;package&#xff09; 声明 java的包&#xff0c;类似电脑系统中的文件夹&#xff0c;包里存放的是类文件。 当类文件很多的时候&#xff0c;通常会采用多个包进行存放管理&#xff0c;这种方式称为分包管理。 在项目中&#xff0c;我们将相同功能的类放到一个…