CLK_OF_DECLARE 解析

本文深入解析了Linux内核中CLK_OF_DECLARE宏的作用及其内部实现原理。从CLK_OF_DECLARE的定义出发,逐步分析其如何通过OF_DECLARE_1和_OF_DECLARE等宏定义,最终形成设备匹配表,用于初始化时钟模块。详细解释了CONFIG_OF配置项的影响,以及这些宏在clk.c、time.c等关键文件中的调用流程。

Linux下系统时钟在初始化时经常用到 CLK_OF_DECLARE 这个宏,现在以 6ul为列做分析:

CLK_OF_DECLARE(imx6ul, "fsl,imx6ul-ccm", imx6ul_clocks_init);

CLK_OF_DECLARE 的定义:

#define CLK_OF_DECLARE(name, compat, fn) OF_DECLARE_1(clk, name, compat, fn)

OF_DECLARE_1 的定义:

typedef void (*of_init_fn_1)(struct device_node *); //函数指针

#define OF_DECLARE_1(table, name, compat, fn) \
		_OF_DECLARE(table, name, compat, fn, of_init_fn_1)

_OF_DECLARE 的定义:

/*
 * Struct used for matching a device
 */
struct of_device_id {
	char	name[32];
	char	type[32];
	char	compatible[128];
	const void *data;
};

#ifdef CONFIG_OF                                        //CONFIG_OF的定义
#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  }
#else
#define _OF_DECLARE(table, name, compat, fn, fn_type)			\
	static const struct of_device_id __of_table_##name		\
		__attribute__((unused))					\
		 = { .compatible = compat,				\
		     .data = (fn == (fn_type)NULL) ? fn : fn }
#endif


定义了一个 struct of_device_id 的结构体变量

如果定义CONFIG_OF,就将 struct of_device_id 变量放到 __clk_of_table 下;

__clk_of_table 在clk.c 文件下的 of_clk_init() 函数中调用:

void __init of_clk_init(const struct of_device_id *matches)
{
.......
	if (!matches)
		matches = &__clk_of_table;
.......
}

of_clk_init 在./arch/arm/kernel/time.c:121:           of_clk_init(NULL); time_init()函数中被调用:


void __init time_init(void)
{
        if (machine_desc->init_time) {
                machine_desc->init_time();
        } else {
#ifdef CONFIG_COMMON_CLK
                of_clk_init(NULL);
#endif
                clocksource_of_init();
        }
}

time_init 在 start_kernel() 函数中被调用 ./init/main.c:587:      time_init();


asmlinkage __visible void __init start_kernel(void)
{
    ............
    time_init();
    ............
}

/** * of_count_phandle_with_args() - Find the number of phandles references in a property * @np: pointer to a device tree node containing a list * @list_name: property name that contains a list * @cells_name: property name that specifies phandles' arguments count * * Returns the number of phandle + argument tuples within a property. It * is a typical pattern to encode a list of phandle and variable * arguments into a single property. The number of arguments is encoded * by a property in the phandle-target node. For example, a gpios * property would contain a list of GPIO specifies consisting of a * phandle and 1 or more arguments. The number of arguments are * determined by the #gpio-cells property in the node pointed to by the * phandle. */ int of_count_phandle_with_args(const struct device_node *np, const char *list_name, const char *cells_name) { struct of_phandle_iterator it; int rc, cur_index = 0; /* * If cells_name is NULL we assume a cell count of 0. This makes * counting the phandles trivial as each 32bit word in the list is a * phandle and no arguments are to consider. So we don't iterate through * the list but just use the length to determine the phandle count. */ if (!cells_name) { const __be32 *list; int size; list = of_get_property(np, list_name, &size); if (!list) return -ENOENT; return size / sizeof(*list); } rc = of_phandle_iterator_init(&it, np, list_name, cells_name, -1); if (rc) return rc; while ((rc = of_phandle_iterator_next(&it)) == 0) cur_index += 1; if (rc != -ENOENT) return rc; return cur_index; } EXPORT_SYMBOL(of_count_phandle_with_args); struct clk *clk_get(struct device *dev, const char *con_id) { const char *dev_id = dev ? dev_name(dev) : NULL; struct clk_hw *hw; if (dev && dev->of_node) { hw = of_clk_get_hw(dev->of_node, 0, con_id); if (!IS_ERR(hw) || PTR_ERR(hw) == -EPROBE_DEFER) return clk_hw_create_clk(dev, hw, dev_id, con_id); } return __clk_get_sys(dev, dev_id, con_id); } 解析以上Linux内核代码,并说明of_clk_get_parent_count函数的功能?
最新发布
10-29
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值