Linux clk子系统(3)--系统调用流程

it2025-10-26  8

目录

1. clk的分类

 2. 系统调用入口

3. leo clk初始化入口

4. of_leo_clocks_init函数leo的clk系统自定义函数

 5. of_clk_init


1. clk的分类

根据clk的特点,clock framework将clock分为fixed rate、gate、devider、mux、fixed factor、composite六类,每一类clock都有相似的功能、相似的控制方式,因而可以使用相同的逻辑,统一处理,这充分体现了面向对象的思想

 2. 系统调用入口

start_kernel--->  time_init

//arch/arm/kernel/time.c void __init time_init(void) { if (machine_desc->init_time) { machine_desc->init_time(); } else { #ifdef CONFIG_COMMON_CLK of_clk_init(NULL); #endif timer_probe(); } }

3. leo clk初始化入口

在leo的移植的操作系统中,在arch/arm/mach-leo/platform_dt.c中定义machine_desc中初始化了init_time.

//arch/arm/mach-leo/platform_dt.c static const char *faraday_dt_match[] __initconst = { "arm,faraday-soc", NULL, }; DT_MACHINE_START(FARADAY, "LEO") .atag_offset = 0x100, .dt_compat = faraday_dt_match, .smp = smp_ops(faraday_smp_ops), .map_io = platform_map_io, .init_time = platform_sys_timer_init, .init_early = platform_init_early, .init_machine = platform_init, .restart = platform_reset, MACHINE_END static void __init platform_sys_timer_init(void) { platform_clock_init(); timer_probe(); } static struct of_device_id faraday_clk_match[] __initconst = { { .compatible = "faraday,leoevb-clk", .data = of_leo_clocks_init, }, {} }; static void __init platform_clock_init(void) { struct device_node *np; const struct of_device_id *match; void (*clk_init)(struct device_node *); /* setup clock tree */ /* 查找设备树对应的设备节点 */ np = of_find_matching_node(NULL, faraday_clk_match); if (!np) panic("unable to find a matching clock\n"); match = of_match_node(faraday_clk_match, np); clk_init = match->data; clk_init(np); //调用of_leo_clocks_init }

4. of_leo_clocks_init函数leo的clk系统自定义函数

/** *driver/clk/faraday/clk-leo.c */ static const __initconst struct of_device_id leo_clk_match[] = { { .compatible = "leo,osc0", .data = of_fixed_clk_setup, }, { .compatible = "leo,rosc0", .data = of_fixed_clk_setup, }, { .compatible = "leo,rosc0_div4", .data = of_fixed_factor_clk_setup, }, { .compatible = "leo,rosc1", .data = of_fixed_clk_setup, }, { .compatible = "leo,audio", .data = of_fixed_clk_setup, }, { .compatible = "leo,pll0", .data = of_leo_faraday_pll_setup, }, { .compatible = "leo,pll1", .data = of_leo_faraday_pll_setup, }, { .compatible = "leo,pll1_div4", .data = of_leo_faraday_pll_setup, }, { .compatible = "leo,pll2", .data = of_leo_faraday_pll_setup, }, { .compatible = "leo,pll2_div5", .data = of_fixed_factor_clk_setup, }, { .compatible = "leo,pll2_div50", .data = of_fixed_factor_clk_setup, }, { .compatible = "leo,pll3", .data = of_leo_faraday_pll_setup, }, { .compatible = "leo,pll4", .data = of_leo_faraday_pll_setup, }, { .compatible = "leo,pll5", .data = of_leo_faraday_pll_setup, }, { .compatible = "leo,pll6", .data = of_leo_faraday_pll_setup, }, { .compatible = "leo,pll7", .data = of_leo_faraday_pll_setup, }, { .compatible = "leo,fastboot", .data = of_leo_faraday_mux_setup, }, { .compatible = "leo,fastboot_div2", .data = of_fixed_factor_clk_setup, }, { .compatible = "leo,ahb", .data = of_leo_faraday_mux_setup, }, { .compatible = "leo,hclk", .data = of_leo_faraday_mux_setup, }, { .compatible = "leo,apb", .data = of_leo_faraday_mux_setup, }, { .compatible = "leo,pclk", .data = of_leo_faraday_mux_setup, }, { .compatible = "leo,cpu", .data = of_leo_faraday_divider_setup, }, { .compatible = "leo,ddrmclk", .data = of_fixed_factor_clk_setup, }, { .compatible = "leo,spiclk", .data = of_leo_faraday_mux_setup, }, { .compatible = "leo,sspclk", .data = of_leo_faraday_mux_setup, }, { .compatible = "leo,sspclk_i2s", .data = of_leo_faraday_mux_setup, }, { .compatible = "leo,sspclk_i2s_1", .data = of_leo_faraday_mux_setup, }, { .compatible = "leo,sdclk", .data = of_leo_faraday_mux_setup, }, { .compatible = "leo,lcclk", .data = of_fixed_factor_clk_setup, }, { .compatible = "leo,gmacclk", .data = of_fixed_factor_clk_setup, }, { .compatible = "leo,uart_uclk_src", .data = of_fixed_factor_clk_setup, }, { .compatible = "leo,uart_uclk_30m", .data = of_leo_faraday_mux_setup, }, { .compatible = "leo,uart_uclk", .data = of_leo_faraday_mux_setup, }, { .compatible = "leo,irda", .data = of_fixed_factor_clk_setup, }, }; void __init of_leo_clocks_init(struct device_node *n) { struct device_node *node; struct of_phandle_args clkspec; struct clk *clk; unsigned long pll0, pll1, pll2, pll3, pll4, pll5, pll6, pll7; unsigned long cpuclk, hclk, pclk, mclk; unsigned long spiclk, sspclk, sspclk_i2s, sdclk; unsigned long lcclk, irdaclk, gmacclk; pll0 = pll1 = pll2 = pll3 = pll4 = pll5 = pll6 = pll7 = 0; cpuclk = hclk = pclk = mclk = 0; spiclk = sspclk = sspclk_i2s = sdclk = 0; lcclk = irdaclk = gmacclk = 0; /* 从自定义的leo_clk_match进行匹配,并执行对应.data字段指定的函数 */ of_clk_init(leo_clk_match); for (node = of_find_matching_node(NULL, leo_clk_match); node; node = of_find_matching_node(node, leo_clk_match)) { clkspec.np = node; clk = of_clk_get_from_provider(&clkspec); of_node_put(clkspec.np); if (!strcmp(__clk_get_name(clk), "pll0")) pll0 = clk_get_rate(clk); else if (!strcmp(__clk_get_name(clk), "pll1")) pll1 = clk_get_rate(clk); else if (!strcmp(__clk_get_name(clk), "pll2")) pll2 = clk_get_rate(clk); else if (!strcmp(__clk_get_name(clk), "pll3")) pll3 = clk_get_rate(clk); else if (!strcmp(__clk_get_name(clk), "pll4")) pll4 = clk_get_rate(clk); else if (!strcmp(__clk_get_name(clk), "pll5")) pll5 = clk_get_rate(clk); else if (!strcmp(__clk_get_name(clk), "pll6")) pll6 = clk_get_rate(clk); else if (!strcmp(__clk_get_name(clk), "pll7")) pll7 = clk_get_rate(clk); else if (!strcmp(__clk_get_name(clk), "cpu")) cpuclk = clk_get_rate(clk); else if (!strcmp(__clk_get_name(clk), "hclk")) hclk = clk_get_rate(clk); else if (!strcmp(__clk_get_name(clk), "pclk")) pclk = clk_get_rate(clk); else if (!strcmp(__clk_get_name(clk), "ddrmclk")) mclk = clk_get_rate(clk); else if (!strcmp(__clk_get_name(clk), "spiclk")) spiclk = clk_get_rate(clk); else if (!strcmp(__clk_get_name(clk), "sspclk")) sspclk = clk_get_rate(clk); else if (!strcmp(__clk_get_name(clk), "sspclk_i2s")) sspclk_i2s = clk_get_rate(clk); else if (!strcmp(__clk_get_name(clk), "sdclk")) sdclk = clk_get_rate(clk); else if (!strcmp(__clk_get_name(clk), "lcclk")) lcclk = clk_get_rate(clk); else if (!strcmp(__clk_get_name(clk), "irda")) irdaclk = clk_get_rate(clk); else if (!strcmp(__clk_get_name(clk), "gmacclk")) gmacclk = clk_get_rate(clk); } printk(KERN_INFO "PLL0: %4ld MHz, PLL1 MCLK: %4ld MHz, PLL2: %4ld MHz, PLL3: %4ld MHz\n", pll0/1000/1000, pll1/1000/1000, pll2/1000/1000, pll3/1000/1000); printk(KERN_INFO "PLL4: %4ld MHz, PLL5 MCLK: %4ld MHz, PLL6: %4ld MHz, PLL7: %4ld MHz\n", pll4/1000/1000, pll5/1000/1000, pll6/1000/1000, pll7/1000/1000); printk(KERN_INFO "CPU: %ld MHz, DDR MCLK: %ld MHz, HCLK: %ld MHz, PCLK: %ld MHz\n", cpuclk/1000/1000, mclk/1000/1000, hclk/1000/1000, pclk/1000/1000); printk(KERN_INFO "SPI CLK: %ld MHz, SSP CLK: %ldMHz, SSP_I2S CLK: %ldMHz, SD CLK: %ldMHz\n", spiclk/1000/1000, sspclk/1000/1000, sspclk_i2s/1000/1000, sdclk/1000/1000); printk(KERN_INFO "LC CLK: %ldMHz, IRDA: %ldMHz , GMAC_REF: %ldMhz\n", lcclk/1000/1000, irdaclk/1000/1000,gmacclk/1000/1000); }

 5. of_clk_init

/** * driver/clk/clk.c */ /** * of_clk_init() - Scan and init clock providers from the DT * @matches: array of compatible values and init functions for providers. * * This function scans the device tree for matching clock providers * and calls their initialization functions. It also does it by trying * to follow the dependencies. */ void __init of_clk_init(const struct of_device_id *matches) { const struct of_device_id *match; struct device_node *np; struct clock_provider *clk_provider, *next; bool is_init_done; bool force = false; LIST_HEAD(clk_provider_list); /** * 如果matches为NULL,则matches指向了.init.data中的__clk_of_table。 * __clk_of_table定义在arch/arm/kernel/vmlinux.lds */ if (!matches) matches = &__clk_of_table; /* First prepare the list of the clocks providers */ for_each_matching_node_and_match(np, matches, &match) { struct clock_provider *parent; if (!of_device_is_available(np)) continue; parent = kzalloc(sizeof(*parent), GFP_KERNEL); if (!parent) { list_for_each_entry_safe(clk_provider, next, &clk_provider_list, node) { list_del(&clk_provider->node); of_node_put(clk_provider->np); kfree(clk_provider); } of_node_put(np); return; } parent->clk_init_cb = match->data; parent->np = of_node_get(np); list_add_tail(&parent->node, &clk_provider_list); } while (!list_empty(&clk_provider_list)) { is_init_done = false; list_for_each_entry_safe(clk_provider, next, &clk_provider_list, node) { if (force || parent_ready(clk_provider->np)) { /* Don't populate platform devices */ of_node_set_flag(clk_provider->np, OF_POPULATED); /** * 依次调用在driver/clk/clk-leo.c中 * leo_clk_match的.data指向的函数 */ clk_provider->clk_init_cb(clk_provider->np); of_clk_set_defaults(clk_provider->np, true); list_del(&clk_provider->node); of_node_put(clk_provider->np); kfree(clk_provider); is_init_done = true; } } /* * We didn't manage to initialize any of the * remaining providers during the last loop, so now we * initialize all the remaining ones unconditionally * in case the clock parent was not mandatory */ if (!is_init_done) force = true; } }

 

最新回复(0)