OK335xS Linux kernel check clock 24M hacking

时间:2023-12-27 23:45:55
/******************************************************************************
* 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 = ; /*
* 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 ; |
} 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(, "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 ; | | | |
} | | | |
| | | |
| | | |
/* 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 ; | | | |
} | | | |
| | | |
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 << ), | | |
.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 = , | | | | |
.ops = &clkops_null, | | | | |
}; | | | | |
v | | | |
static const struct clksel_rate div_1_1_rates[] = { | | | |
{ .div = , .val = , .flags = RATE_IN_AM33XX }, | | | |
{ .div = }, | | | |
}; | | | |
| | | |
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 = ; | |
| |
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 = ; | | |
} | | |
} | | |
} | | |
| | |
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 ; | |
} | |
| |
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);