OK335xS Linux kernel check clock 24M hacking
/****************************************************************************** * OK335xS Linux kernel check clock 24M hacking * 声明: * 由于需要确认kernel中的时钟和引脚配置的时钟是否一致,于是需要去跟踪内核 * 中的代码是如何对引脚配置时钟进行识别,并对其进行相关配置的额。 * * 2016-1-5 深圳 南山平山村 曾剑锋 *****************************************************************************/ MACHINE_START(AM335XEVM, "am335xevm") /* Maintainer: Texas Instruments */ .atag_offset = 0x100, .map_io = am335x_evm_map_io, .init_early = am33xx_init_early, ---------------+ .init_irq = ti81xx_init_irq, | .handle_irq = omap3_intc_handle_irq, | .timer = &omap3_am33xx_timer, | .init_machine = am335x_evm_init, | MACHINE_END | | void __init am33xx_init_early(void) <--------------+ { omap2_set_globals_am33xx(); omap3xxx_check_revision(); am33xx_check_features(); omap_common_init_early(); am33xx_voltagedomains_init(); omap44xx_prminst_init(); am33xx_powerdomains_init(); omap44xx_cminst_init(); am33xx_clockdomains_init(); am33xx_hwmod_init(); omap_hwmod_init_postsetup(); omap3xxx_clk_init(); --------------+ } | | int __init omap3xxx_clk_init(void) <-------------+ { struct omap_clk *c; u32 cpu_clkflg = 0; /* * 3505 must be tested before 3517, since 3517 returns true * for both AM3517 chips and AM3517 family chips, which * includes 3505. Unfortunately there's no obvious family * test for 3517/3505 :-( */ if (cpu_is_omap3505()) { cpu_mask = RATE_IN_34XX; cpu_clkflg = CK_3505; } else if (cpu_is_omap3517()) { cpu_mask = RATE_IN_34XX; cpu_clkflg = CK_3517; } else if (cpu_is_omap3505()) { cpu_mask = RATE_IN_34XX; cpu_clkflg = CK_3505; } else if (cpu_is_omap3630()) { cpu_mask = (RATE_IN_34XX | RATE_IN_36XX); cpu_clkflg = CK_36XX; } else if (cpu_is_ti816x()) { cpu_mask = RATE_IN_TI816X; cpu_clkflg = CK_TI816X; } else if (cpu_is_am33xx()) { am33xx_clk_init(); ---------------------------+ return 0; | } else if (cpu_is_ti814x()) { | cpu_mask = RATE_IN_TI814X; | } else if (cpu_is_omap34xx()) { | if (omap_rev() == OMAP3430_REV_ES1_0) { | cpu_mask = RATE_IN_3430ES1; | cpu_clkflg = CK_3430ES1; | } else { | /* | * Assume that anything that we haven't matched yet | * has 3430ES2-type clocks. | */ | cpu_mask = RATE_IN_3430ES2PLUS; | cpu_clkflg = CK_3430ES2PLUS; | } | } else { | WARN(1, "clock: could not identify OMAP3 variant\n"); | } | ...... | } | | int __init am33xx_clk_init(void) <-----------------------+ { struct omap_clk *c; u32 cpu_clkflg; if (cpu_is_am33xx()) { cpu_mask = RATE_IN_AM33XX; cpu_clkflg = CK_AM33XX; } clk_init(&omap2_clk_functions); ------------------------+ | for (c = am33xx_clks; c < am33xx_clks + ARRAY_SIZE(am33xx_clks); c++)--*---+ clk_preinit(c->lk.clk); | | | | for (c = am33xx_clks; c < am33xx_clks + ARRAY_SIZE(am33xx_clks); c++) | | if (c->cpu & cpu_clkflg) { | | clkdev_add(&c->lk); | | clk_register(c->lk.clk); | | omap2_init_clk_clkdm(c->lk.clk); ----------------*-+ | } | | | | | | recalculate_root_clocks(); | | | | | | /* | | | * Only enable those clocks we will need, let the drivers | | | * enable other clocks as necessary | | | */ | | | clk_enable_init_clocks(); -------------------------*-*-*-+ | | | | return 0; | | | | } | | | | | | | | | | | | /* Common data */ | | | | | | | | struct clk_functions omap2_clk_functions = { <------------------+ | | | .clk_enable = omap2_clk_enable, | | | | .clk_disable = omap2_clk_disable, | | | | .clk_round_rate = omap2_clk_round_rate, | | | | .clk_set_rate = omap2_clk_set_rate, | | | | .clk_set_parent = omap2_clk_set_parent, | | | | .clk_disable_unused = omap2_clk_disable_unused, | | | | #ifdef CONFIG_CPU_FREQ | | | | /* These will be removed when the OPP code is integrated */ | | | | .clk_init_cpufreq_table = omap2_clk_init_cpufreq_table, | | | | .clk_exit_cpufreq_table = omap2_clk_exit_cpufreq_table, | | | | #endif | | | | }; | | | | | | | | static struct clk_functions *arch_clock; --------------*-*-*-*-+ int __init clk_init(struct clk_functions * custom_clocks) <-------------+ | | | | { | | | | if (!custom_clocks) { | | | | pr_err("No custom clock functions registered\n"); | | | | BUG(); | | | | } | | | | | | | | arch_clock = custom_clocks; | | | | | | | | return 0; | | | | } | | | | | | | | void omap2_init_clk_clkdm(struct clk *clk) <--------------------------+ | | | { | | | struct clockdomain *clkdm; | | | | | | if (!clk->clkdm_name) | | | return; | | | | | | clkdm = clkdm_lookup(clk->clkdm_name); -------+ | | | if (clkdm) { | | | | printk("clock: associated clk %s to clkdm %s\n", | | | | clk->name, clk->clkdm_name); | | | | pr_debug("clock: associated clk %s to clkdm %s\n", | | | | clk->name, clk->clkdm_name); | | | | clk->clkdm = clkdm; | | | | } else { | | | | pr_debug("clock: could not associate clk %s to " | | | | "clkdm %s\n", clk->name, clk->clkdm_name); | | | | } | | | | } | | | | | | | | struct clockdomain *clkdm_lookup(const char *name) <------+ | | | { | | | struct clockdomain *clkdm, *temp_clkdm; | | | | | | if (!name) | | | return NULL; | | | | | | clkdm = NULL; | | | | | | list_for_each_entry(temp_clkdm, &clkdm_list, node) { | | | if (!strcmp(name, temp_clkdm->name)) { | | | clkdm = temp_clkdm; | | | break; | | | } | | | } | | | | | | return clkdm; | | | } | | | | | | | | | /* | | | * clkdev +----------------------------------------------------------+ | | | */ | | | | | static struct omap_clk am33xx_clks[] = { <---------------*-+ | | ...... | | | CLK(NULL, "clk_rc32k_ck", &clk_rc32k_ck, CK_AM33XX), | | | CLK(NULL, "virt_19_2m_ck", &virt_19_2m_ck, CK_AM33XX), | | | CLK(NULL, "virt_24m_ck", &virt_24m_ck, CK_AM33XX), | | | CLK(NULL, "virt_25m_ck", &virt_25m_ck, CK_AM33XX), | | | CLK(NULL, "virt_26m_ck", &virt_26m_ck, CK_AM33XX), | | | CLK(NULL, "sys_clkin_ck", &sys_clkin_ck, CK_AM33XX), ----+ | | | CLK(NULL, "tclkin_ck", &tclkin_ck, CK_AM33XX), | | | | CLK(NULL, "dpll_core_ck", &dpll_core_ck, CK_AM33XX), | | | | CLK(NULL, "dpll_core_x2_ck", &dpll_core_x2_ck, CK_AM33XX), | | | | CLK(NULL, "dpll_core_m4_ck", &dpll_core_m4_ck, CK_AM33XX), | | | | CLK(NULL, "dpll_core_m5_ck", &dpll_core_m5_ck, CK_AM33XX), | | | | CLK(NULL, "dpll_core_m6_ck", &dpll_core_m6_ck, CK_AM33XX), | | | | CLK(NULL, "sysclk1_ck", &sysclk1_ck, CK_AM33XX), | | | | CLK(NULL, "sysclk2_ck", &sysclk2_ck, CK_AM33XX), | | | | ...... | | | | }; | | | | | +-----------------------------------------+ | | | | struct omap_clk { | <-------------*-+ | | u16 cpu; | | | | struct clk_lookup lk; | | | | }; | | | | | | | | #define CLK(dev, con, ck, cp) \ <----+ | | | { \ | | | .cpu = cp, \ | | | .lk = { \ | | | .dev_id = dev, \ | | | .con_id = con, \ | | | .clk = ck, \ | | | }, \ | | | } | | | | | | /* sys_clk_in */ | | | static struct clk sys_clkin_ck = { <------------------+ | | .name = "sys_clkin_ck", | | .parent = &virt_24m_ck, | | .init = &omap2_init_clksel_parent, ----------------------+ | | /** | | | * +------------------------------------------------------------------------+ | | | * | Table 9-14. control_status Register Field Descriptions | | | | * +-------+----------+------------+----------------------------------------+ | | | * | Bit | Field | Type Reset | Description | | | | * +-------+----------+------------+----------------------------------------+ | | | * | 23-22 | sysboot1 | R/W 0h | Used to select crystal clock frequency.| | | | * | | | | See SYSBOOT Configuration Pins. | | | | * | | | | Reset value is from SYSBOOT[15:14]. | | | | * +-------+----------+------------+----------------------------------------+ | | | */ | | | .clksel_reg = AM33XX_CTRL_REGADDR(0x40), /* CONTROL_STATUS */ | | | .clksel_mask = (0x3 << 22), | | | .clksel = sys_clkin_sel, -----------+ | | | .ops = &clkops_null, -----------*-----+ | | | .recalc = &omap2_clksel_recalc, | | | | | }; | | | | | | | | | | /* Oscillator clock */ | | | | | /* 19.2, 24, 25 or 26 MHz */ | | | | | static const struct clksel sys_clkin_sel[] = { <----+ | | | | { .parent = &virt_19_2m_ck, .rates = div_1_0_rates }, | | | | { .parent = &virt_24m_ck, .rates = div_1_1_rates }, | ------+ | | | { .parent = &virt_25m_ck, .rates = div_1_2_rates }, | | | | | { .parent = &virt_26m_ck, .rates = div_1_3_rates }, | | | | | { .parent = NULL }, | | | | | | }; | | | | | | | | | | | | static struct clk virt_24m_ck = { | <--------*---------+ | | | .name = "virt_24m_ck", | | | | | .rate = 24000000, | | | | | .ops = &clkops_null, | | | | | }; | | | | | v | | | | static const struct clksel_rate div_1_1_rates[] = { | | | | { .div = 1, .val = 1, .flags = RATE_IN_AM33XX }, | | | | { .div = 0 }, | | | | }; | | | | | | | | const struct clkops clkops_null = { <----------+ | | | .enable = clkll_enable_null, | | | .disable = clkll_disable_null, | | | }; | | | | | | | | | // 到目前为止都不知道哪里调用了这个函数,因为这个函数是用来判断系统接入的晶振 | | | // 大小的,没跟踪到到底是谁调用了该函数。 | | | void omap2_init_clksel_parent(struct clk *clk) <--------------------+ | | { | | const struct clksel *clks; | | const struct clksel_rate *clkr; | | u32 r, found = 0; | | | | if (!clk->clksel || !clk->clksel_mask) | | return; | | | | r = __raw_readl(clk->clksel_reg) & clk->clksel_mask; | | r >>= __ffs(clk->clksel_mask); | | | | for (clks = clk->clksel; clks->parent && !found; clks++) { | | for (clkr = clks->rates; clkr->div && !found; clkr++) { | | if (!(clkr->flags & cpu_mask)) | | continue; | | | | if (clkr->val == r) { | | if (clk->parent != clks->parent) { | | pr_debug("clock: inited %s parent " | | "to %s (was %s)\n", | | clk->name, clks->parent->name, | | ((clk->parent) ? | | clk->parent->name : "NULL")); | | clk_reparent(clk, clks->parent); ------------+ | | }; | | | found = 1; | | | } | | | } | | | } | | | | | | printk("zengjf ckeck function calling [%s].\n", __func__); | | | /* This indicates a data error */ | | | WARN(!found, "clock: %s: init parent: could not find regval %0x\n", | | | clk->name, r); | | | | | | return; | | | } | | | | | | int clk_reparent(struct clk *c, struct clk *parent) <-----------+ | | { | | c->parent = parent; | | return 0; | | } | | | | void clk_enable_init_clocks(void) <-------------------+ | { | struct clk *clkp; | | list_for_each_entry(clkp, &clocks, node) { | if (clkp->flags & ENABLE_ON_INIT) | clk_enable(clkp); -------+ | } | | } | | | | /* | | * Standard clock functions defined in include/linux/clk.h | | */ | | | | int clk_enable(struct clk *clk) <------+ | { | unsigned long flags; | int ret; | | if (clk == NULL || IS_ERR(clk)) | return -EINVAL; | | if (!arch_clock || !arch_clock->clk_enable) | return -EINVAL; | | spin_lock_irqsave(&clockfw_lock, flags); | ret = arch_clock->clk_enable(clk); <----------------------+ spin_unlock_irqrestore(&clockfw_lock, flags); return ret; } EXPORT_SYMBOL(clk_enable);