zoukankan      html  css  js  c++  java
  • linux clk时钟源管理

    硬件资源越来越庞大和复杂,内核的另一个挑战就是要便捷的管理这些资源。同时,面对如此之多的平台不同的CPU,管理机制需要统一适用,这就需要对资源的管理抽象到更加通用的层次。CPU中各个模块都需要时钟驱动,内核需要一种机制能通用所有的平台,方便的管理CPU上所有的clk资源。这里分析Linux对clk的管理。
    Linux version: 2.6.38
    平台: i.mx53 (mxc),以下所有平台相关部分都特指i.mx53
    涉及的源文件有:
    • include/linux/clk.h
    • drivers/clk/clkdev.c
    • arch/arm/plat-mxc/clock.c
    • arch/arm/mach-mx5/clock.c
    1. clk通用接口

    内核定义了一套标准的接口(include/linux/clk.h),用于所有的平台之上。每个时钟源对象使用一个struct clk结构来表示。而struct clk结构的具体内容由各平台自己定义。clk.h头文件定义了操作一个clk对象的所有接口。内核的其他地方可以也只能使用clk.h中提供的这些接口函数来操作clk。

    struct clk *clk_get(struct device *dev, const char *id);
    int clk_enable(struct clk *clk);
    void clk_disable(struct clk *clk);
    unsigned long clk_get_rate(struct clk *clk);
    void clk_put(struct clk *clk);
    long clk_round_rate(struct clk *clk, unsigned long rate);
    int clk_set_rate(struct clk *clk, unsigned long rate);
    int clk_set_parent(struct clk *clk, struct clk *parent);
    struct clk *clk_get_parent(struct clk *clk);
    struct clk *clk_get_sys(const char *dev_id, const char *con_id);
    int clk_add_alias(const char *alias, const char *alias_dev_name, char *id,
    			struct device *dev);
    


    2. struct clk

    clk结构体是平台相关的。在arch/arm/mach-mx5/clock.c中会预先描述CPU中所有的clk对象。

    • parent - clk是由parent分出来的。那么如果parent关闭了,当前clk也就没有了。
    • secondary - 第二时钟源,用于enable/disable当前clk。
    • usecount - 引用计数。
    • get_rate, set_rate, enable, disable, set_parent - 很显然,这些函数指针指到实际操作的函数。clk.h中的各接口函数最后都会调用到这里的函数指针。函数指针是隔离变化的最好办法,在这里一下就把层次抽象出来了。

    2. clocks链表

    arch/arm/mach-mx5/clock.c中不仅定义了所有的clk对象,而且每个clk对象还要对应一个struct clk_lookup结构。在初始化时,会将所有的clk_loopup结构添加进入clocks链表中。

    struct clk_lookup {
    	struct list_head	node;
    	const char		*dev_id;
    	const char		*con_id;
    	struct clk		*clk;
    };

    clk_lookup,顾名思义就知道它是用来查找struct clk结构的。有了它,就可以通过设备名或时钟源的名字来找到相应的struct clk结构。链表操作位于drivers/clk/clkdev.c


    3. clk平台通用操作

    arch/arm/plat-mxc/clock.c源文件中定义了mxc平台clock的通用操作接口。

    enable/disable函数中可以看到引用计数usecount的作用。一个clk只有当其usecount为0的时候才会做实际的打开动作,也只有usecount为0时才能确认没有被任何其他设备使用,可以禁止了。层次关系被递归调用和引用计数巧妙的实现。

    static void __clk_disable(struct clk *clk)
    {
    	if (clk == NULL || IS_ERR(clk))
    		return;
    	WARN_ON(!clk->usecount);
    
    	if (!(--clk->usecount)) {
    		if (clk->disable)
    			clk->disable(clk);
    
    		__clk_disable(clk->secondary);
    		__clk_disable(clk->parent);
    	}
    }
    
    static int __clk_enable(struct clk *clk)
    {
    	if (clk == NULL || IS_ERR(clk))
    		return -EINVAL;
    
    	if (clk->usecount++ == 0) {
    		__clk_enable(clk->parent);
    		__clk_enable(clk->secondary);
    
    		if (clk->enable)
    			clk->enable(clk);
    	}
    	return 0;
    }
    

    4. clk与pm

    为了省电,当不需要clk时将其关闭,上面的clk_enable/clk_disable实现了此功能。除了关闭clk省电,还可以降低clk频率以达到省电的目的。当系统当前负载较轻,不需要clk跑在那么高的频率时,就可以对该clk降频了。从这些关系可以看到,clk与电源管理,cpufreq等都可能有关联。

    mxc为各时钟定义了几个属性标志:

    arch/arm/plat-mxc/include/mach/clock.h

    /* Clock flags */
    #define RATE_PROPAGATES		(1 << 0)	/* Program children too */
    #define ALWAYS_ENABLED		(1 << 1)	/* Clock cannot be disabled */
    #define RATE_FIXED		(1 << 2)	/* Fixed clock rate */
    #define CPU_FREQ_TRIG_UPDATE	(1 << 3)	/* CPUFREQ trig update */
    #define AHB_HIGH_SET_POINT	(1 << 4)	/* Requires max AHB clock */
    #define AHB_MED_SET_POINT	(1 << 5)	/* Requires med AHB clock */


  • 相关阅读:
    Java数据库小项目02--管家婆项目
    Java数据库小项目01--实现用户登录注册
    Java数据库小项目00---基础知识
    MySQL基础练习02---牛客网
    ICMP
    语法糖
    双绞线
    telnet 时代的 bbs
    ARPA
    IEEE802是一个局域网标准系列
  • 原文地址:https://www.cnblogs.com/sammei/p/3295612.html
Copyright © 2011-2022 走看看