时钟四

接下来该分析time_init了

/arch/arm/kernel/time.c

void __init time_init(void)
{
#ifndef CONFIG_GENERIC_TIME
        if (system_timer->offset == NULL)
                system_timer->offset = dummy_gettimeoffset;
#endif
        system_timer->init();
}

大家看到这是不是傻眼了,

system_timer->init(),此函数在setup_arch中被赋值了,此值在Machine_init中有定义

功能为初始化系统时钟,以及注册各个时钟单元 clk_register();

/arch/arm/mach-mx5/mach-mx51_3stage.c

static void __init mx51_3stack_timer_init(void)
{
        struct clk *uart_clk;

        /* Change the CPU voltages for TO2*/
        if (cpu_is_mx51_rev(CHIP_REV_2_0) <= 1) {
                cpu_wp_auto[0].cpu_voltage = 1175000;
                cpu_wp_auto[1].cpu_voltage = 1100000;
                cpu_wp_auto[2].cpu_voltage = 1000000;
        }

        mx51_clocks_init(32768, 24000000, 22579200, 24576000);

        uart_clk = clk_get(NULL, "uart_clk.0");
        early_console_setup(UART1_BASE_ADDR, uart_clk);
}

static struct sys_timer mxc_timer = {
        .init   = mx51_3stack_timer_init,
};

MACHINE_START(MX51_3DS, "Freescale MX51 3-Stack Board")
        /* Maintainer: Freescale Semiconductor, Inc. */
        .phys_io = AIPS1_BASE_ADDR,
        .io_pg_offst = ((AIPS1_BASE_ADDR_VIRT) >> 18) & 0xfffc,
        .fixup = fixup_mxc_board,
        .map_io = mx5_map_io,
        .init_irq = mx5_init_irq,
        .init_machine = mxc_board_init,
        .timer = &mxc_timer,
MACHINE_END
/arch/arm/mach-mx5/clock.c

int __init mx51_clocks_init(unsigned long ckil, unsigned long osc, unsigned long ckih1, unsigned long ckih2)
{
        __iomem void *base;
        struct clk **clkp, *tclk;
        int i = 0, j = 0, reg;
        int wp_cnt = 0;

        pll1_base = ioremap(PLL1_BASE_ADDR, SZ_4K);
        pll2_base = ioremap(PLL2_BASE_ADDR, SZ_4K);
        pll3_base = ioremap(PLL3_BASE_ADDR, SZ_4K);

        /* Turn off all possible clocks */
        if (mxc_jtag_enabled) {
                __raw_writel(1 << MXC_CCM_CCGR0_CG0_OFFSET |
                              1 << MXC_CCM_CCGR0_CG1_OFFSET |
                              1 << MXC_CCM_CCGR0_CG2_OFFSET |
                              3 << MXC_CCM_CCGR0_CG3_OFFSET |
                              3 << MXC_CCM_CCGR0_CG4_OFFSET |
                              3 << MXC_CCM_CCGR0_CG8_OFFSET |
                              3 << MXC_CCM_CCGR0_CG9_OFFSET |
                              1 << MXC_CCM_CCGR0_CG12_OFFSET |
                              1 << MXC_CCM_CCGR0_CG13_OFFSET |
                              1 << MXC_CCM_CCGR0_CG14_OFFSET, MXC_CCM_CCGR0);
        } else {
                __raw_writel(1 << MXC_CCM_CCGR0_CG0_OFFSET |
                              1 << MXC_CCM_CCGR0_CG1_OFFSET |
                              1 << MXC_CCM_CCGR0_CG2_OFFSET |
                              3 << MXC_CCM_CCGR0_CG3_OFFSET |
                              3 << MXC_CCM_CCGR0_CG8_OFFSET |
                              3 << MXC_CCM_CCGR0_CG9_OFFSET |
                              1 << MXC_CCM_CCGR0_CG12_OFFSET |
                              1 << MXC_CCM_CCGR0_CG13_OFFSET |
                              3 << MXC_CCM_CCGR0_CG14_OFFSET, MXC_CCM_CCGR0);
        }
        __raw_writel(0, MXC_CCM_CCGR1);
        __raw_writel(0, MXC_CCM_CCGR2);
        __raw_writel(0, MXC_CCM_CCGR3);
        __raw_writel(1 << MXC_CCM_CCGR4_CG8_OFFSET, MXC_CCM_CCGR4);

        __raw_writel(1 << MXC_CCM_CCGR5_CG2_OFFSET |
                     1 << MXC_CCM_CCGR5_CG6_1_OFFSET |
                     1 << MXC_CCM_CCGR5_CG6_2_OFFSET |
                     3 << MXC_CCM_CCGR5_CG7_OFFSET |
                     1 << MXC_CCM_CCGR5_CG8_OFFSET |
                     3 << MXC_CCM_CCGR5_CG9_OFFSET |
                     1 << MXC_CCM_CCGR5_CG10_OFFSET |
                     3 << MXC_CCM_CCGR5_CG11_OFFSET, MXC_CCM_CCGR5);

        __raw_writel(1 << MXC_CCM_CCGR6_CG4_OFFSET, MXC_CCM_CCGR6);

        ckil_clk.rate = ckil;
        osc_clk.rate = osc;
        ckih_clk.rate = ckih1;
        ckih2_clk.rate = ckih2;

        /* Fix up clocks unique to MX51. */
        esdhc2_clk[0].recalc = _clk_esdhc2_recalc;
        esdhc2_clk[0].set_rate = _clk_esdhc2_set_rate;

        emi_intr_clk[1].name = "emi_garb_clk";
        clk_tree_init();

        for (clkp = mxc_clks; clkp < mxc_clks + ARRAY_SIZE(mxc_clks); clkp++)
                clk_register(*clkp);

        clk_register(&fpm_clk);
        clk_register(&fpm_div2_clk);

 clk_register(&hsi2c_clk);
        clk_register(&hsi2c_serial_clk);
        clk_register(&sim_clk[0]);
        clk_register(&sim_clk[1]);
        clk_register(&mipi_hsc1_clk);
        clk_register(&mipi_hsc2_clk);
        clk_register(&mipi_esc_clk);
        clk_register(&mipi_hsp_clk);
        clk_register(&spdif1_clk[0]);
        clk_register(&spdif1_clk[1]);
        clk_register(&ddr_hf_clk);

        max_axi_a_clk = MAX_AXI_A_CLK_MX51;
        max_axi_b_clk = MAX_AXI_B_CLK_MX51;

        /* set DDR clock parent */
        reg = 0;
        if (cpu_is_mx51_rev(CHIP_REV_2_0) >= 1) {
                reg = __raw_readl(MXC_CCM_CBCDR) & MXC_CCM_CBCDR_DDR_HF_SEL;
                reg >>= MXC_CCM_CBCDR_DDR_HF_SEL_OFFSET;


                if (reg)
                        tclk = &ddr_hf_clk;
        }
        if (reg == 0) {
                reg = __raw_readl(MXC_CCM_CBCMR) &
                                        MXC_CCM_CBCMR_DDR_CLK_SEL_MASK;
                reg >>= MXC_CCM_CBCMR_DDR_CLK_SEL_OFFSET;

                if (reg == 0) {
                        tclk = &axi_a_clk;
                } else if (reg == 1) {
                        tclk = &axi_b_clk;
                } else if (reg == 2) {
                        tclk = &emi_slow_clk;
                } else {
                        tclk = &ahb_clk;
                }
        }
        clk_set_parent(&ddr_clk, tclk);

        /*Setup the LPM bypass bits */
        reg = __raw_readl(MXC_CCM_CLPCR);

 

        reg |= MXC_CCM_CLPCR_BYPASS_HSC_LPM_HS
                | MXC_CCM_CLPCR_BYPASS_IPU_LPM_HS
                | MXC_CCM_CLPCR_BYPASS_RTIC_LPM_HS
                | MXC_CCM_CLPCR_BYPASS_SCC_LPM_HS_MX51
                | MXC_CCM_CLPCR_BYPASS_SDMA_LPM_HS_MX51;
        __raw_writel(reg, MXC_CCM_CLPCR);

        /* Disable the handshake with HSC block as its not
          * initialised right now.
          */
        reg = __raw_readl(MXC_CCM_CCDR);
        reg |= MXC_CCM_CCDR_HSC_HS_MASK;
        __raw_writel(reg, MXC_CCM_CCDR);

        /* This will propagate to all children and init all the clock rates */
        propagate_rate(&osc_clk);
        propagate_rate(&ckih_clk);
        propagate_rate(&ckih2_clk);
        propagate_rate(&ckil_clk);
        propagate_rate(&pll1_sw_clk);
        propagate_rate(&pll2_sw_clk);

        clk_enable(&cpu_clk);

 

        /* Set SDHC parents to be PLL2 */
        clk_set_parent(&esdhc1_clk[0], &pll2_sw_clk);
        clk_set_parent(&esdhc2_clk[0], &pll2_sw_clk);

        /* set SDHC root clock as 166.25MHZ*/
        clk_set_rate(&esdhc1_clk[0], 166250000);
        clk_set_rate(&esdhc2_clk[0], 166250000);

        /* Initialise the parents to be axi_b, parents are set to
         * axi_a when the clocks are enabled.
         */
        clk_set_parent(&vpu_clk[0], &axi_b_clk);
        clk_set_parent(&vpu_clk[1], &axi_b_clk);
        clk_set_parent(&gpu3d_clk, &axi_a_clk);
        clk_set_parent(&gpu2d_clk, &axi_a_clk);

        /* move cspi to 24MHz */
        clk_set_parent(&cspi_main_clk, &lp_apm_clk);
        clk_set_rate(&cspi_main_clk, 12000000);
        /*move the spdif0 to spdif_xtal_ckl */
        clk_set_parent(&spdif0_clk[0], &spdif_xtal_clk);
        /*set the SPDIF dividers to 1 */
        reg = __raw_readl(MXC_CCM_CDCDR);

 

        reg &= ~MXC_CCM_CDCDR_SPDIF0_CLK_PODF_MASK;
        reg &= ~MXC_CCM_CDCDR_SPDIF0_CLK_PRED_MASK;
        __raw_writel(reg, MXC_CCM_CDCDR);

        /* move the spdif1 to 24MHz */
        clk_set_parent(&spdif1_clk[0], &spdif_xtal_clk);
        /* set the spdif1 dividers to 1 */
        reg = __raw_readl(MXC_CCM_CDCDR);
        reg &= ~MXC_CCM_CDCDR_SPDIF1_CLK_PODF_MASK;
        reg &= ~MXC_CCM_CDCDR_SPDIF1_CLK_PRED_MASK;
        __raw_writel(reg, MXC_CCM_CDCDR);

        /* Move SSI clocks to SSI_LP_APM clock */
        clk_set_parent(&ssi_lp_apm_clk, &lp_apm_clk);

        clk_set_parent(&ssi1_clk[0], &ssi_lp_apm_clk);
        /* set the SSI dividers to divide by 2 */
        reg = __raw_readl(MXC_CCM_CS1CDR);
        reg &= ~MXC_CCM_CS1CDR_SSI1_CLK_PODF_MASK;
        reg &= ~MXC_CCM_CS1CDR_SSI1_CLK_PRED_MASK;
        reg |= 1 << MXC_CCM_CS1CDR_SSI1_CLK_PRED_OFFSET;

        __raw_writel(reg, MXC_CCM_CS1CDR);

        clk_set_parent(&ssi2_clk[0], &ssi_lp_apm_clk);
        reg = __raw_readl(MXC_CCM_CS2CDR);
        reg &= ~MXC_CCM_CS2CDR_SSI2_CLK_PODF_MASK;
        reg &= ~MXC_CCM_CS2CDR_SSI2_CLK_PRED_MASK;
        reg |= 1 << MXC_CCM_CS2CDR_SSI2_CLK_PRED_OFFSET;
        __raw_writel(reg, MXC_CCM_CS2CDR);

        /* Change the SSI_EXT1_CLK to be sourced from SSI1_CLK_ROOT */
        clk_set_parent(&ssi_ext1_clk, &ssi1_clk[0]);
        clk_set_parent(&ssi_ext2_clk, &ssi2_clk[0]);

        /* move usb_phy_clk to 24MHz */
        clk_set_parent(&usb_phy_clk[0], &osc_clk);

        /* set usboh3_clk to pll2 */
        clk_set_parent(&usboh3_clk[0], &pll2_sw_clk);
        reg = __raw_readl(MXC_CCM_CSCDR1);
        reg &= ~MXC_CCM_CSCDR1_USBOH3_CLK_PODF_MASK;
        reg &= ~MXC_CCM_CSCDR1_USBOH3_CLK_PRED_MASK;

 

       reg |= 4 << MXC_CCM_CSCDR1_USBOH3_CLK_PRED_OFFSET;
        reg |= 1 << MXC_CCM_CSCDR1_USBOH3_CLK_PODF_OFFSET;
        __raw_writel(reg, MXC_CCM_CSCDR1);

        /* Set the current working point. */
        cpu_wp_tbl = get_cpu_wp(&cpu_wp_nr);
        /* Update the cpu working point table based on the PLL1 freq
         * at boot time
         */
        if (pll1_main_clk.rate <= cpu_wp_tbl[cpu_wp_nr - 1].cpu_rate)
                wp_cnt = 1;
        else if (pll1_main_clk.rate <= cpu_wp_tbl[1].cpu_rate &&
                                pll1_main_clk.rate > cpu_wp_tbl[2].cpu_rate)
                wp_cnt = cpu_wp_nr - 1;
        else
                wp_cnt = cpu_wp_nr;

        cpu_wp_tbl[0].cpu_rate = pll1_main_clk.rate;

        if (wp_cnt == 1) {
                cpu_wp_tbl[0] = cpu_wp_tbl[cpu_wp_nr - 1];

 

                memset(&cpu_wp_tbl[cpu_wp_nr - 1], 0, sizeof(struct cpu_wp));
                memset(&cpu_wp_tbl[cpu_wp_nr - 2], 0, sizeof(struct cpu_wp));
        } else if (wp_cnt < cpu_wp_nr) {
                for (i = 0; i < wp_cnt; i++)
                        cpu_wp_tbl[i] = cpu_wp_tbl[i+1];
                memset(&cpu_wp_tbl[i], 0, sizeof(struct cpu_wp));
        }

        if (wp_cnt < cpu_wp_nr) {
                set_num_cpu_wp(wp_cnt);
                cpu_wp_tbl = get_cpu_wp(&cpu_wp_nr);
        }


        for (j = 0; j < cpu_wp_nr; j++) {
                if ((ddr_clk.parent == &ddr_hf_clk)) {
                        /* Change the CPU podf divider based on the boot up
                         * pll1 rate.
                         */
                        cpu_wp_tbl[j].cpu_podf =
                                (pll1_main_clk.rate / cpu_wp_tbl[j].cpu_rate)

 

                                - 1;
                        if (pll1_main_clk.rate/(cpu_wp_tbl[j].cpu_podf + 1) >
                                        cpu_wp_tbl[j].cpu_rate) {
                                cpu_wp_tbl[j].cpu_podf++;
                                cpu_wp_tbl[j].cpu_rate =
                                         pll1_main_clk.rate/
                                         (1000 * (cpu_wp_tbl[j].cpu_podf + 1));
                                cpu_wp_tbl[j].cpu_rate *= 1000;
                        }
                        if (pll1_main_clk.rate/(cpu_wp_tbl[j].cpu_podf + 1) <
                                                cpu_wp_tbl[j].cpu_rate) {
                                cpu_wp_tbl[j].cpu_rate = pll1_main_clk.rate;
                        }
                }
        cpu_wp_tbl[j].pll_rate = pll1_main_clk.rate;
        }
        /* Set the current working point. */
        for (i = 0; i < cpu_wp_nr; i++) {
                if (clk_get_rate(&cpu_clk) == cpu_wp_tbl[i].cpu_rate) {
                        cpu_curr_wp = i;
                        break;

 

               }
        }
        if (i > cpu_wp_nr)
                BUG();

        clk_set_parent(&arm_axi_clk, &axi_a_clk);
        clk_set_parent(&ipu_clk[0], &axi_b_clk);

        if (uart_at_24) {
                /* Move UART to run from lp_apm */
                clk_set_parent(&uart_main_clk, &lp_apm_clk);

                /* Set the UART dividers to divide, so the UART_CLK is 24MHz. */
                reg = __raw_readl(MXC_CCM_CSCDR1);
                reg &= ~MXC_CCM_CSCDR1_UART_CLK_PODF_MASK;
                reg &= ~MXC_CCM_CSCDR1_UART_CLK_PRED_MASK;
                reg |= (0 << MXC_CCM_CSCDR1_UART_CLK_PRED_OFFSET) |
                    (0 << MXC_CCM_CSCDR1_UART_CLK_PODF_OFFSET);
                __raw_writel(reg, MXC_CCM_CSCDR1);
        } else {
                /* Move UART to run from PLL1 */

                /* Move UART to run from PLL1 */
                clk_set_parent(&uart_main_clk, &pll1_sw_clk);

                /* Set the UART dividers to divide,
                 * so the UART_CLK is 66.5MHz.
                 */
                reg = __raw_readl(MXC_CCM_CSCDR1);
                reg &= ~MXC_CCM_CSCDR1_UART_CLK_PODF_MASK;
                reg &= ~MXC_CCM_CSCDR1_UART_CLK_PRED_MASK;
                reg |= (5 << MXC_CCM_CSCDR1_UART_CLK_PRED_OFFSET) |
                    (1 << MXC_CCM_CSCDR1_UART_CLK_PODF_OFFSET);
                __raw_writel(reg, MXC_CCM_CSCDR1);
        }

        propagate_rate(&osc_clk);
        propagate_rate(&pll1_sw_clk);
        propagate_rate(&pll2_sw_clk);

 

        clk_set_parent(&emi_slow_clk, &ahb_clk);
        clk_set_rate(&emi_slow_clk, clk_round_rate(&emi_slow_clk, 130000000));

        /* Change the NFC clock rate to be 1:4 ratio with emi clock. */
        clk_set_rate(&emi_enfc_clk, clk_round_rate(&emi_enfc_clk,
                        (clk_get_rate(&emi_slow_clk))/4));

        base = ioremap(GPT1_BASE_ADDR, SZ_4K);
        mxc_timer_init(&gpt_clk[0], base, MXC_INT_GPT);
        return 0;
}

终于贴完了,真他妈的长貌似也没多大用处,还是自己好好分析吧

void __init mxc_timer_init(struct clk *timer_clk, void __iomem *base, int irq)
{
        uint32_t tctl_val;

        clk_enable(timer_clk);

        if (cpu_is_mx1()) {
#ifdef CONFIG_ARCH_MX1
                timer_base = IO_ADDRESS(TIM1_BASE_ADDR);
                irq = TIM1_INT;
#endif
        } else if (cpu_is_mx2()) {
#ifdef CONFIG_ARCH_MX2
                timer_base = IO_ADDRESS(GPT1_BASE_ADDR);
                irq = MXC_INT_GPT1;
#endif
        } else if (cpu_is_mx3()) {
#ifdef CONFIG_ARCH_MX3
                timer_base = IO_ADDRESS(GPT1_BASE_ADDR);
                irq = MXC_INT_GPT;

#endif
        }
        if (base) {
                timer_base = base;
        }

        /*
         * Initialise to a known state (all timers off, and timing reset)
         */

        __raw_writel(0, timer_base + MXC_TCTL);
        __raw_writel(0, timer_base + MXC_TPRER); /* see datasheet note */

        if (timer_is_v2())
                tctl_val = MX3_TCTL_CLK_PER | MX3_TCTL_FRR | MX3_TCTL_WAITEN | MXC_TCTL_TEN;
        else
                tctl_val = MX1_2_TCTL_FRR | MX1_2_TCTL_CLK_PCLK1 | MXC_TCTL_TEN;

        __raw_writel(tctl_val, timer_base + MXC_TCTL);

        /* init and register the timer to the framework */

 

        /* init and register the timer to the framework */
        mxc_clocksource_init(timer_clk);
        mxc_clockevent_init(timer_clk);

        /* Make irqs happen */
        setup_irq(irq, &mxc_timer_irq);    //设置系统定时的中断函数
}

static struct irqaction mxc_timer_irq = {
        .name           = "i.MX Timer Tick",
        .flags          = IRQF_DISABLED | IRQF_TIMER | IRQF_IRQPOLL,
        .handler        = mxc_timer_interrupt,
};

static irqreturn_t mxc_timer_interrupt(int irq, void *dev_id)
{
        struct clock_event_device *evt = &clockevent_mxc;
        uint32_t tstat;

        if (timer_is_v2())
                tstat = __raw_readl(timer_base + MX3_TSTAT);
        else
                tstat = __raw_readl(timer_base + MX1_2_TSTAT);

        gpt_irq_acknowledge();

        evt->event_handler(evt);    //这里就是系统中断,里面完成了好多东西,包括软中断的执行系统调用

        return IRQ_HANDLED;
}

 

static int __init mxc_clockevent_init(struct clk *timer_clk)
{
        unsigned int c = clk_get_rate(timer_clk);

        if (timer_is_v2())
                clockevent_mxc.set_next_event = mx3_set_next_event;

        clockevent_mxc.mult = div_sc(c, NSEC_PER_SEC,
                                        clockevent_mxc.shift);
        clockevent_mxc.max_delta_ns =
                        clockevent_delta2ns(0xfffffffe, &clockevent_mxc);
        clockevent_mxc.min_delta_ns =
                        clockevent_delta2ns(0xff, &clockevent_mxc);

        clockevent_mxc.cpumask = cpumask_of(0);

        clockevents_register_device(&clockevent_mxc);   //向通知链中注册自己,同时设置自己的event_handler这个就是在那里定下来的里面完成了软件中断操作,系统调度等任务

        return 0;
}

 static struct clock_event_device clockevent_mxc = {
        .name           = "mxc_timer1",
        .features       = CLOCK_EVT_FEAT_ONESHOT,
        .shift          = 32,
        .set_mode       = mxc_set_mode,
        .set_next_event = mx1_2_set_next_event,
        .rating         = 200,
};

最后贴一下别人总结的一点东西

clockevents_register_device()

clockevents_do_notify(CLOCK_EVT_NOTIFY_ADD, dev);

//通知注册回调的人执行当时注册的回调函数 tick_notify()

raw_notifier_call_chain(&clockevents_chain, reason, dev);   

tick_notify()                

tick_check_new_device()

           tick_setup_device()

                  tick_setup_periodic()

                         tick_set_periodic_handler()

                                dev->event_handler = tick_handle_periodic;

tick_handle_periodic()

tick_periodic

           do_timer                       /*更新jiffies */

                  update_wall_time

           update_process_times    /*计算进程耗时,, 重新计算调度时间片等等 */

                  run_local_timers()  //执行所有的软件timer

                  clockevents_program_event()

                            ->set_next_event                  //设置下一次事件(周期性的)

 

 

 

 

 

 

 


 

 

 

 


 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值