Linux EMMC子系统分析-初始化流程

最近在解EMMC的一个bug,发现Linux EMMC有点小复杂,先整理个文档出来吧

用的是TI 平台,仅分析MMC,不分析SD和SDIO


mmc_init

2769 static int __init mmc_init(void)
2770 {
2774 
2775     workqueue = alloc_ordered_workqueue("kmmcd", 0);
2776     if (!workqueue)
2777         return -ENOMEM;
2778 
2779     ret = mmc_register_bus();
2780     if (ret)
2781         goto destroy_workqueue;
2782 
2783     ret = mmc_register_host_class();
2784     if (ret)
2785         goto unregister_bus;;
2793 

2802 }

2775分配一个workqueue,这个workqueue是专门用来处理card detect的,EMMC因为是unremovable的,所以不需要关注它

2779 注册mmc_bus_type,实现如下:

int mmc_register_bus(void)
{
    return bus_register(&mmc_bus_type);
}
把mmc_bus_type注册到bus系统,后面调用device_add函数时,则会辗转调用到mmc_bus_type中的probe函数,不必太纠结在这个代码


mmc_init调用时间比较早,会在host驱动初始化之前执行完。

subsys_initcall(mmc_init);

host驱动初始化

kernel/drivers/mmc/host/omap_hsmmc.c

host驱动位置是kernel/drivers/mmc/host/,一般来说都是platform_driver,以omap hsmmc host驱动为例

    <strong>.probe      = omap_hsmmc_probe,</strong>
    .remove     = omap_hsmmc_remove,
    .driver     = {
        .name = DRIVER_NAME,
        .owner = THIS_MODULE,
        .pm = &omap_hsmmc_dev_pm_ops,
        .of_match_table = of_match_ptr(omap_mmc_of_match),
    },
};

module_platform_driver(omap_hsmmc_driver);

只需要关注omap_hsmmc_probe即可,当系统匹配到platform_device时,会调用omap_hsmmc_probe,好长的一个函数

2627     base = devm_ioremap_resource(&pdev->dev, res);
2628     if (IS_ERR(base))
2629         return PTR_ERR(base);
2630 
2631     ret = omap_hsmmc_gpio_init(pdata);
2632     if (ret)
2633         goto err;
devm_ioremap_resource,实质就是ioremap,设备特定io资源到内核地址的映射,自行脑补一下ioremap。

omap_hsmmc_gpio_init是card detect和write protect gpio的初始化,Ignore it!!!

2635     mmc = mmc_alloc_host(sizeof(struct omap_hsmmc_host), &pdev->dev);
2636     if (!mmc) {
2637         ret = -ENOMEM;
2638         goto err_alloc;
2639     }
...............
mmc_alloc_host,分配一个omap_hsmmc_host结构(包含struct mmc_host),以供后面玩耍

2661     mmc->ops    = &omap_hsmmc_ops;

2410 static const struct mmc_host_ops omap_hsmmc_ops = {
2411     .enable = omap_hsmmc_enable_fclk,
2412     .disable = omap_hsmmc_disable_fclk,
2413     .post_req = omap_hsmmc_post_req,
2414     .pre_req = omap_hsmmc_pre_req,
2415     .request = omap_hsmmc_request,
2416     .set_ios = omap_hsmmc_set_ios,
2417     .get_cd = omap_hsmmc_get_cd,
2418     .get_ro = omap_hsmmc_get_ro,
2419     .init_card = omap_hsmmc_init_card,
2420     .start_signal_voltage_switch = omap_start_signal_voltage_switch,
2421     .card_busy = omap_hsmmc_card_busy,
2422     .execute_tuning = omap_execute_tuning,
2423     /* NYET -- enable_sdio_irq */
2424 };
 omap hsmmc host驱动和mmc子系统的所有接口都在这里了。

2663     mmc->f_min = OMAP_MMC_MIN_CLOCK;

2675     if (pdata->max_freq > 0) {
2676         mmc->f_max = pdata->max_freq;
2677         ret = clk_set_rate(host->fclk, pdata->max_freq);
2678         if (ret) {
2679             dev_err(dev, "failed to set clock to %d\n",
2680                 pdata->max_freq);
2681             goto err1;
2682         }
2683     } else {
2684         mmc->f_max = OMAP_MMC_MAX_CLOCK;
2685     }


定义了最小时钟400K,在系统初始化阶段为了兼容的原因会使用这个时钟。最大时钟为52MHZ,后面还有机会再修改这个时钟频率。

2724     mmc->max_segs = 1024;
2725 
2726     mmc->max_blk_size = 512;       /* Block Length at max can be 1024 */
2727     mmc->max_blk_count = 0xFFFF;    /* No. of Blocks is 16 bits */
2728     mmc->max_req_size = mmc->max_blk_size * mmc->max_blk_count;
2729     mmc->max_seg_size = mmc->max_req_size;

mmc作为快设备,最主要的操作就是数据sectors读写,max_segs定义了block设备的request所支持的最大segment

max_blk_count 一个request中所包含的最大block数

其实多少都不重要,反正就是和request相关的一些上限。


                
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值