Linux的移植(3)

  1. 时钟驱动
    1. 硬件无关部分
    2. 硬件相关部分
  2. dmaengine

时钟驱动

在SoC中,晶振、PLL、驱动和门等会形成一个时钟树形结构,针对时钟部件碎片化的问题,Linux实现了一套统一的时钟框架,称为通用时钟。

这套统一的时钟框架包含两部分:硬件无关时钟定义及API硬件相关接口及回调

硬件无关部分

在内核中,时钟在软件层被抽象成了clk结构体,其主要是作为clk核心层内部的描述。同时还有时钟的操作接口的定义,这些接口向上为上层软件提供统一的时钟操作API,向下为硬件驱动实现提供标准的驱动实现框架。其定义如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36

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);
int (*save_context)(struct clk_hw *hw);
void (*restore_context)(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);
int (*get_duty_cycle)(struct clk_hw *hw,
struct clk_duty *duty);
int (*set_duty_cycle)(struct clk_hw *hw,
struct clk_duty *duty);
void (*init)(struct clk_hw *hw);
void (*debug_init)(struct clk_hw *hw, struct dentry *dentry);
};

硬件相关部分

对于具体SoC而言,需要去实现自己SoC的clk驱动,clk驱动的实现采用内核提供的clk框架,在clk框架中,clk_hw用于驱动中对于硬件时钟的描述,在clk驱动中主要实现的是硬件的初始化和将clk硬件实例注册到clk子系统的核心层。在clk核心层中,clk结构体就将clk硬件和clk相关操作联系起来,使得上层软件接口与下层硬件接口相通。clk_hw的定义如下所示。

1
2
3
4
5
struct clk_hw {
struct clk_core *core;
struct clk *clk;
const struct clk_init_data *init;
}

从clk核心层到具体芯片clk驱动的调用顺序为:

clk_enable(clk)=》clk->ops->enable(clk->hw)

目前内核通常通过设备树来描述电路板上的时钟树,以及时钟与设备之间的绑定关系。因此在clk驱动中需要从设备树获取相关信息,注册时钟控制器为一个时钟树的提供者,并建立各个时钟与索引的映射。

要分析clk驱动的具体实现,可参考drivers/clk/目录下的各不同平台关于clk驱动的实现。

dmaengine

dmaengine是一套通用的DMA驱动框架,该框架为具体使用DMA通道的设备驱动提供了一套统一的API,而且定义了用具体的DMA控制器实现这一套API的方法。

我们可以基于dmaengine所定义的标准化的DMA控制方法,来简单地实现各种类型的DMA传输工作。对于特定硬件DMA驱动,所要完成的主要工作就是实现封装在内核dma_device结构体中的那些成员函数。

dma_device实例通过dma_async_device_register()接口注册;在其中的成员函数中,一般通过链表管理DMA描述符的运行、free等队列;成员函数device_issue_pending()用于实现DMA传输开启的功能;当DMA传输完成后,驱动中注册的中断服务程序的顶半部和或底半部会调用DMA描述符dma_async_tx_descriptor中设置的回调函数。

典型的dmaengine驱动可参考drivers/dma/sirf-dma.c、drivers/dma/omap-dma.c等


转载请注明来源,欢迎对文章中的引用来源进行考证,欢迎指出任何有错误或不够清晰的表达。可以在下面评论区评论,也可以邮件至 yxhlfx@163.com

文章标题:Linux的移植(3)

本文作者:红尘追风

发布时间:2016-12-21, 18:49:28

原始链接:http://www.micernel.com/2016/12/21/Linux%E7%9A%84%E7%A7%BB%E6%A4%8D(3)/

版权声明: "署名-非商用-相同方式共享 4.0" 转载请保留原文链接及作者。

目录