• 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
Logo

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

更多推荐