sdio (三) linux sdio 驱动
sdio在linux中的位置drivers/mmc里面结构很清晰cardcorehostcard 是 卡host 是 sdio 控制器(适配器)core 是 card 和 host 中用的函数用户空间的sdio(提起这个词,好久没有说过了,感觉离linux越来越远,稍微有些伤感)wit@vexpress:/ # ls /dev/mmcblk0/dev/mmc...
·
- sdio在linux中的位置
drivers/mmc里面结构很清晰,三个目录 card core host
card 是 卡 // 如果要开发 sd卡驱动,此目录不用关注,因为 sd 卡 的协议是标准的,所以sd卡的驱动也是标准的,几个文件可以代表所有的卡
host 是 sdio 控制器(适配器)// 如果要开发 sd卡驱动,此目录需要关注,此目录为sd host 的驱动
core 是 card 和 host 中用的函数 //如果要开发 sd卡 驱动,此目录不用关注
所以我们说的sd卡驱动开发,其实本质是 sd host 驱动开发
- sd存储卡初始化过程(按代码运行顺序排序)
1/ mmc core 子系统的初始化 // 唯一的一个
drivers/mmc/core/core.c subsys_initcall(mmc_init);
2/ card 初始化 // 所有的卡的过程都是相同的,所以此文件不需要变化
drivers/mmc/card/block.c module_init(mmc_blk_init);
3/ host 初始化 // 根据host 不同而不同
drivers/mmc/host/mmci.c module_amba_driver(mmci_driver);
vexpress(vexpress-v2p-ca9) 平台的 sd卡驱动示例
- 设备树
// 设备树 在 mmci_probe->mmci_of_parse->mmc_of_parse 被解析
vexpress-v2p-ca9.dts
vexpress-v2m.dtsi
mmci@05000 {
compatible = "arm,pl180", "arm,primecell";
reg = <0x05000 0x1000>;
interrupts = <9 10>;
cd-gpios = <&v2m_mmc_gpios 0 0>;
wp-gpios = <&v2m_mmc_gpios 1 0>;
max-frequency = <12000000>;
vmmc-supply = <&v2m_fixed_3v3>;
clocks = <&v2m_clk24mhz>, <&smbclk>;
clock-names = "mclk", "apb_pclk";
};
// vexpress 其他核心板
vexpress-v2p-ca15_a7.dts vexpress-v2p-ca15-tc1.dts vexpress-v2p-ca5s.dts
vexpress-v2m-rs1.dtsi
mmci@050000 {
compatible = "arm,pl180", "arm,primecell";
reg = <0x050000 0x1000>;
interrupts = <9 10>;
cd-gpios = <&v2m_mmc_gpios 0 0>;
wp-gpios = <&v2m_mmc_gpios 1 0>;
max-frequency = <12000000>;
vmmc-supply = <&v2m_fixed_3v3>;
clocks = <&v2m_clk24mhz>, <&smbclk>;
clock-names = "mclk", "apb_pclk";
};
- 初始化流程
mmc初始化后到启动前的mmc 相关过程都是 从 mmc_rescan 开始的.
mmc_rescan 是mmc_alloc_host时 INIT_DELAYED_WORK(&host->detect, mmc_rescan); 做出来的任务
该任务会被后的这一句被分配任务队列上去,mmc_schedule_delayed_work(&host->detect, delay);
至于 谁调用的 mmc_schedule_delayed_work ,以及 调用了之后流程是怎么走的(在mmc_start_request中加dump_stack),是需要关注的,下面就是答案
// mmci 模块(drivers/mmc/host/mmci.c)中的函数
mmci_probe
mmc_add_host
mmc_start_host
_mmc_detect_change
mmc_schedule_delayed_work(&host->detect, delay); // 开始调度任务. // 此行的dealy 为 0
0延时之后开始任务任务(该任务做sd卡的初始化cmd0->cmd8->acmd41->cmd2->cmd3->cmd9->cmd7)
实际做的初始化包括(CMD52 CMD52 CMD0 CMD8 CMD5 CMD55 CMD41 CMD0 CMD8 CMD55 CMD41 CMD2 CMD3 CMD9 CMD7 CMD55 CMD51 CMD55 CMD13 )
做完初始化之后,任务退出之前,恰好上层主动做了一次 cmd18.
在任务的最后,mmc_schedule_delayed_work(&host->detect, delay);开始做下一次预约.下一次的时候 mmc_rescan仍然会执行,但是mmc_rescan 执行还没到初始化就退出了, 第三次也是这样子...所以只能初始化一次 // 此行的 dealy为 1s.
- 初始化 之后的 读块(多块读)
linux 中没有实现单块读(?),单块读实现(但是单块读肯定是必要的)的本质是多块读.(cmd18,cmd12)
实际上走的命令包括(CMD18 CMD12)
[22:47:09][<c0025380>] (unwind_backtrace) from [<c001dfa4>] (show_stack+0x2c/0x38)
[22:47:09][<c001dfa4>] (show_stack) from [<c05a1ca4>] (__dump_stack+0x1c/0x24)
[22:47:09][<c05a1ca4>] (__dump_stack) from [<c05a1d7c>] (dump_stack+0xd0/0xf8)
[22:47:09][<c05a1d7c>] (dump_stack) from [<c0854580>] (mmc_start_request+0x14/0x57c)
[22:47:09][<c0854580>] (mmc_start_request) from [<c0854dcc>] (__mmc_start_data_req+0x38/0x70)
[22:47:09][<c0854dcc>] (__mmc_start_data_req) from [<c0855674>] (mmc_start_req+0x1e4/0x2a0)
[22:47:09][<c0855674>] (mmc_start_req) from [<c087952c>] (mmc_blk_issue_rw_rq+0x184/0x7d4)
[22:47:09][<c087952c>] (mmc_blk_issue_rw_rq) from [<c0879e80>] (mmc_blk_issue_rq+0x304/0x364)
[22:47:09][<c0879e80>] (mmc_blk_issue_rq) from [<c087b5d8>] (mmc_queue_thread+0x17c/0x2a0)
[22:47:09][<c087b5d8>] (mmc_queue_thread) from [<c0080d24>] (kthread+0x240/0x24c)
[22:47:09][<c0080d24>] (kthread) from [<c0015700>] (ret_from_fork+0x14/0x34)
mmc_queue_thread 是什么时候 做出来的.
mmc_blk_probe(drivers/mmc/card/block.c)
md = mmc_blk_alloc // 创建了一个md,其中包含一个线程
mmc_blk_alloc_req
mmc_init_queue
mq->thread = kthread_run(mmc_queue_thread, mq, "mmcqd/%d%s", host->index, subname ? subname : "");
mmc_add_disk(md) // 向系统注册这个线程.
其他
1.subsys_initcall(mmc_init);
对mmc设备进行初始化
2.module_init(mmc_blk_init);
对mmc块模块进行初始化
3.挂载mmc设备驱动
驱动程序中的xx_mmc_probe
检测host设备中挂载的sd设备
mmc_alloc_host // 创建一个host设备
INIT_DELAYED_WORK(&host->detect, mmc_rescan)
1.mmc_attach_sd // 对卡进行初始化
2.mmc_add_card // 把存储卡加到系统中。正式与系统驱动连接在一起。
3.mmc_blk_probe // 通知mmc块设备驱动。
- 中断
host/mmci.c:1712: ret = devm_request_irq(&dev->dev, dev->irq[0], mmci_irq, IRQF_SHARED,
host/mmci.c:1720: ret = devm_request_irq(&dev->dev, dev->irq[1], mmci_pio_irq,
# cat /proc/interrupts
CPU0
34: 729 GIC 41 mmci-pl18x (cmd)
35: 43778 GIC 42 mmci-pl18x (pio)
- 需要关注的打印
2235 pr_info("%s: %s %s partition %u %s\n",
2236 part_md->disk->disk_name, mmc_card_id(card),
2237 mmc_card_name(card), part_md->part_type, cap_str);
/*
2441 pr_info("%s: %s %s %s %s\n",
2442 md->disk->disk_name /*mmcblk0*/, mmc_card_id(card)/*mmc0:4567*/, mmc_card_name(card)/*QEMU!*/,
2443 cap_str/*25.0 MiB*/, md->read_only ? "(ro)" : "");
*/
mmcblk0: mmc0:4567 QEMU! 25.0 MiB
mmc_blk_probe
pr_info("%s: %s %s %s %s\n",
md->disk->disk_name, mmc_card_id(card), mmc_card_name(card),
cap_str, md->read_only ? "(ro)" : "");
mmc_blk_alloc_parts
mmc_blk_alloc_part
pr_info("%s: %s %s partition %u %s\n",
part_md->disk->disk_name, mmc_card_id(card),
mmc_card_name(card), part_md->part_type, cap_str);
- 读多块log
[07:19:04]mmc0: starting CMD18 arg 01000c00 flags 000000b5
[07:19:04]mmc0: blksz 512 blocks 2 flags 00000200 tsac 100 ms nsac 0
[07:19:04]mmc0: CMD12 arg 00000000 flags 00000095
[07:19:04]mmci-pl18x 10005000.mmci: blksz 0200 blks 0002 flags 00000200
[07:19:04]mmci-pl18x 10005000.mmci: op 12 arg 01000c00 flags 000000b5
[07:19:04]mmci-pl18x 10005000.mmci: irq0 (data+cmd) 00000040
[07:19:04]mmci-pl18x 10005000.mmci: irq0 (data+cmd) 00000000
[07:19:04]mmci-pl18x 10005000.mmci: irq1 (pio) 0022a400
[07:19:04]mmci-pl18x 10005000.mmci: irq1 (pio) 0022a400
[07:19:04]mmci-pl18x 10005000.mmci: irq1 (pio) 0022a400
[07:19:04]mmci-pl18x 10005000.mmci: irq1 (pio) 0022a400
[07:19:04]mmci-pl18x 10005000.mmci: irq1 (pio) 0022a400
[07:19:04]mmci-pl18x 10005000.mmci: irq1 (pio) 0022a400
[07:19:04]mmci-pl18x 10005000.mmci: irq1 (pio) 0022a400
[07:19:04]mmci-pl18x 10005000.mmci: irq1 (pio) 0022a400
[07:19:04]mmci-pl18x 10005000.mmci: irq1 (pio) 0022a400
[07:19:04]mmci-pl18x 10005000.mmci: irq1 (pio) 0022a400
[07:19:04]mmci-pl18x 10005000.mmci: irq1 (pio) 0022a400
[07:19:04]mmci-pl18x 10005000.mmci: irq1 (pio) 0022a400
[07:19:04]mmci-pl18x 10005000.mmci: irq1 (pio) 0022a400
[07:19:04]mmci-pl18x 10005000.mmci: irq1 (pio) 0022a400
[07:19:04]mmci-pl18x 10005000.mmci: irq1 (pio) 0022a400
[07:19:04]mmci-pl18x 10005000.mmci: irq1 (pio) 0022a500
[07:19:04]mmci-pl18x 10005000.mmci: irq0 (data+cmd) 00000100
[07:19:04]mmci-pl18x 10005000.mmci: op 0c arg 00000000 flags 00000095
[07:19:04]mmci-pl18x 10005000.mmci: irq0 (data+cmd) 00000140
[07:19:04]mmc0: req done (CMD18): 0: 00000900 00000000 00000000 00000000
[07:19:04]mmc0: 1024 bytes transferred: 0
[07:19:04]mmc0: (CMD12): 0: 00000b00 00000000 00000000 00000000
[07:19:04]mmci-pl18x 10005000.mmci: irq0 (data+cmd) 00000000
- mmci 模块初始化log
[07:19:02]suws_kernel sd drivers/mmc/host/mmci.c,mmci_probe,1519
[07:19:02]mmci-pl18x 10005000.mmci: "bus-width" property is missing, assuming 1 bit.
[07:19:02]mmci-pl18x 10005000.mmci: Got CD GPIO
[07:19:02]mmci-pl18x 10005000.mmci: Got WP GPIO
[07:19:02]mmci-pl18x 10005000.mmci: designer ID = 0x41
[07:19:02]mmci-pl18x 10005000.mmci: revision = 0x0
[07:19:02]mmci-pl18x 10005000.mmci: clocking block at 12000000 Hz
[07:19:02]mmci-pl18x 10005000.mmci: No vqmmc regulator found
[07:19:02]mmci-pl18x 10005000.mmci: mmc0: PL181 manf 41 rev0 at 0x10005000 irq 34,35 (pio)
[07:19:02]mmc0: clock 0Hz busmode 2 powermode 1 cs 0 Vdd 21 width 0 timing 0
[07:19:02]suws_kernel sd drivers/mmc/host/mmci.c,mmci_probe,1743

魔乐社区(Modelers.cn) 是一个中立、公益的人工智能社区,提供人工智能工具、模型、数据的托管、展示与应用协同服务,为人工智能开发及爱好者搭建开放的学习交流平台。社区通过理事会方式运作,由全产业链共同建设、共同运营、共同享有,推动国产AI生态繁荣发展。
更多推荐
所有评论(0)