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

本文详细介绍了Linux EMMC子系统的初始化流程,包括mmc_init函数的执行,工作队列的分配,mmc_bus_type的注册,以及host驱动如omap_hsmmc的初始化。内容涉及iomap资源映射,GPIO初始化,mmc_host结构分配,时钟频率设定,DMA通道配置,以及中断处理函数的设置。文章最后讲解了mmc卡的探测和添加过程,包括设置设备地址,获取CSD和CID,读取EXT_CSD,以及建立mmc设备和block设备的关联。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

最近在解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驱动为例

.probe = omap_hsmmc_probe,

.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相关的一些上限。

2731 mmc->caps |= MMC_CAP_MMC_HIGHSPEED | MMC_CAP_SD_HIGHSPEED |

2732 MMC_CAP_WAIT_WHILE_BUSY | MMC_CAP_ERASE;

2733

2734 mmc->caps |=

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值