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);

 

posted on 2016-01-05 16:44  zengjf  阅读(445)  评论(0编辑  收藏  举报

导航