2410的初始化流程(设备初始化)

来源:互联网 发布:c语言在线手册 编辑:程序博客网 时间:2024/04/30 06:13

 

2410的初始化流程

1 mach-smdk2410.c中先通过MACHINE_START()定义了machine_desc的变量,其中注册了smdk2410_map_io(), s3c2410_init_irq(), smdk2410_init()3个回调函数. 3个回调函数会在系统起来的时候setup_arch()里面逐个调用来进行虚实地址映射, 中断初始化, clock初始化,片上设备的注册等操作.

/*向系统注册一个machine_desc的对象*/

MACHINE_START(SMDK2410, "SMDK2410") /* @TODO: request a new identifier and switch

                    * to SMDK2410 */

    /* Maintainer: Jonas Dietsche */

    .phys_io    = S3C2410_PA_UART,

    .io_pg_offst    = (((u32)S3C24XX_VA_UART) >> 18) & 0xfffc,

    .boot_params    = S3C2410_SDRAM_PA + 0x100,

    .map_io     = smdk2410_map_io, 

    .init_irq   = s3c24xx_init_irq,

    .init_machine   = smdk_machine_init,

    .timer      = &s3c24xx_timer,

MACHINE_END

 

2 smdk2410_map_io()   用来静态remap物理地址和虚拟地址, 初始化clockuart, 调用顺序为: arch/arm/kernel/ setup.c: Setup_arch()->paging_init()->devicemaps_init()->mdesc->map_io()->smdk2410_map_io().

static void __init smdk2410_map_io(void)

{

    s3c24xx_init_io(smdk2410_iodesc, ARRAY_SIZE(smdk2410_iodesc));

    s3c24xx_init_clocks(0);

    s3c24xx_init_uarts(smdk2410_uartcfgs, ARRAY_SIZE(smdk2410_uartcfgs));

    s3c24xx_set_board(&smdk2410_board);

}

a) 首先调用s3c24xx_init_io()->s3c2410_map_io()来映射虚实地址, 最终映射好的虚实地址为 (s3c2410_iodesc[])

S3C24XX_VA_CLKPWR  --> __phys_to_pfn(S3C24XX_PA_CLKPWR), size S3C24XX_SZ_CLKPWR

S3C24XX_VA_LCD  --> __phys_to_pfn(S3C24XX_PA_LCD), size S3C24XX_SZ_LCD

S3C24XX_VA_TIMER  --> __phys_to_pfn(S3C24XX_PA_ TIMER), size S3C24XX_SZ_ TIMER

S3C24XX_VA_WATCHDOG  --> __phys_to_pfn(S3C24XX_PA_ WATCHDOG), size S3C24XX_SZ_ WATCHDOG

如果我们要加入我们自己的映射,只要在smdk2410_iodesc[]添加就行了, 以后如果某个资源没有映射也可以在相应的驱动种用ioremap()来动态映射(很多驱动都是这么做的)

b) 接着调用s3c24xx_init_clocks()->s3c2410_init_clocks()来初始化clock:

void __init s3c2410_init_clocks(int xtal)

{

   

       /* now we've got our machine bits initialised, work out what

        * clocks we've got */

 

       fclk = s3c2410_get_pll(__raw_readl(S3C2410_MPLLCON), xtal);

 

       tmp = __raw_readl(S3C2410_CLKDIVN);

 

       /* work out clock scalings */

 

       hclk = fclk / ((tmp & S3C2410_CLKDIVN_HDIVN) ? 2 : 1);

       pclk = hclk / ((tmp & S3C2410_CLKDIVN_PDIVN) ? 2 : 1);

 

       /* print brieft summary of clocks, etc */

 

       printk("S3C2410: core %ld.%03ld MHz, memory %ld.%03ld MHz, peripheral %ld.%03ld MHz/n",

              print_mhz(fclk), print_mhz(hclk), print_mhz(pclk));

 

       /* initialise the clocks here, to allow other things like the

        * console to use them

        */

 

       s3c24xx_setup_clocks(xtal, fclk, hclk, pclk);     /*把相关时钟资源添加到clocks list中去*/

       s3c2410_baseclk_add();    /*把相关时钟资源添加到clocks list中去*/

}

时钟资源添加入系统后, 每个驱动在初始化时会到这个list中去着属于自己的clock并打开它.

c) 随后调用s3c24xx_init_uarts()->s3c2410_init_uarts()->s3c24xx_init_uartdevs()

void __init s3c24xx_init_uartdevs(char *name,

                  struct s3c24xx_uart_resources *res,

                  struct s3c2410_uartcfg *cfg, int no)

{

    struct platform_device *platdev;

    struct s3c2410_uartcfg *cfgptr = uart_cfgs; /*全局数组,保存串口的配置信息*/

    struct s3c24xx_uart_resources *resp;

    int uart;

 

/*把配置信息保存起来,包括对寄存器的设置值*/

    memcpy(cfgptr, cfg, sizeof(struct s3c2410_uartcfg) * no);

 

    for (uart = 0; uart < no; uart++, cfg++, cfgptr++) {

        /*为每个uartplatform_device设置好相关值*/

platdev = s3c24xx_uart_src[cfgptr->hwport];

 

        resp = res + cfgptr->hwport;

 

        s3c24xx_uart_devs[uart] = platdev;

       

        platdev->name = name;

        platdev->resource = resp->resources;

        platdev->num_resources = resp->nr_resources;

 

        platdev->dev.platform_data = cfgptr;

    }

 

    nr_uarts = no;

}

d) 最后调用s3c24xx_set_board(), 这个函数相对简单, 它查看smdk2410_board下有没有clock资源,有的话也添加到clocks list中去

 

3 s3c2410_init_irq()   用来初始化irq,  调用顺序为: arch/arm/kernel/ setup.c  :   setup_arch():init_arch_irq = mdesc->init_irq()  -> init_IRQ()->init_arch_irq()->s3c24xx_init_irq(). 详细流程可以参考另一片文章

<< 2410下的中断流程.doc >>

4 smdk2410_init():  调用顺序为: arch/arm/kernel/ setup.c   

setup_arch():init_machine = mdesc-> init_machine () -> customize_machine() -> init_machine()->smdk_machine_init ()

void __init smdk_machine_init(void)

{

    /* Configure the LEDs (even if we have no LED support)*/

    /*配置相关GPIO*/

    s3c2410_gpio_cfgpin(S3C2410_GPF4, S3C2410_GPF4_OUTP);

    s3c2410_gpio_cfgpin(S3C2410_GPF5, S3C2410_GPF5_OUTP);

    s3c2410_gpio_cfgpin(S3C2410_GPF6, S3C2410_GPF6_OUTP);

    s3c2410_gpio_cfgpin(S3C2410_GPF7, S3C2410_GPF7_OUTP);

   

    /*设置默认的GPIO*/

    s3c2410_gpio_setpin(S3C2410_GPF4, 1);

    s3c2410_gpio_setpin(S3C2410_GPF5, 1);

    s3c2410_gpio_setpin(S3C2410_GPF6, 1);

    s3c2410_gpio_setpin(S3C2410_GPF7, 1);

 

    /*初始化nand设备信息, 在驱动里的probe中会用到*/

    s3c_device_nand.dev.platform_data = &smdk_nand_info; 

 

/*

* 把设备添加进系统里去,这样以后相应的驱动注册后就可以匹配到相关设备, 以后我们要添加什

* 么设备也可以添加到smdk_devs 数组中, smdk_devs 下的每个设备都静态定义好了它自己的所有

* 资源,包括寄存器地址, 中断号等, 在驱动probe到后就可以使用这些资源来操作这个设备了

*/

    platform_add_devices(smdk_devs, ARRAY_SIZE(smdk_devs)); 

 

    s3c2410_pm_init();/*电源管理方面的初始化*/

}

这样以后,nand驱动等注册后就可以找到自己的设备, 并加以使用起来

原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 wi-fi信号差怎么办 无线dns未响应怎么办 影客票务过期怎么办 默认主页改不了怎么办 快递派件不成功怎么办 韵达快递不派件怎么办 中通快递不派件怎么办 理财回执单丢失怎么办 理财回单丢了怎么办 杭州市老年优待卡怎么办 网络连接不到服务器怎么办 即时库存有负数怎么办 电脑软件被拦截怎么办 超市无条码商品怎么办 场外期权有诈骗怎么办 ip地址访问受限怎么办 电脑ip地址受限怎么办 百度云资源打不开怎么办 百度网盘看文件字太小怎么办 密码输入三次错误怎么办 notes邮箱满了怎么办 小米8买不到怎么办 小米付款不发货怎么办 小米金融还款中怎么办 股票遇到闪崩怎么办 微信插件没有怎么办 excel打印太小怎么办 工地临时人员死亡怎么办 哺乳期乳腺增生疼怎么办 哺乳期有乳腺增生怎么办 哺乳期得了乳腺增生怎么办 中等教育认证花名册丢失怎么办 哺乳期囊性结节怎么办 乳腺增生堵奶怎么办 月子期乳房增生怎么办 母乳期乳腺增生怎么办 上市公司破产了股票怎么办 iptv错误码30022怎么办 电信iptv不清晰怎么办 电信iptv卡顿怎么办 pr滚动字幕闪烁怎么办