【转】简单分析与移植rockchip平台mmc/sd卡

版权声明:本文为博主原创文章,转载请注明出处:https://blog.csdn.net/huang_165/article/details/86550606

环境:
sd卡:罗果 128MB class 6
内核:Linux4.4

class 6是sd卡数据速率标准


我们先看看硬件拓扑图:图片转自http://www.wowotech.net/basic_tech/mmc_sd_sdio_intro.html

【转】简单分析与移植rockchip平台mmc/sd卡_第1张图片

      MMC的本质是提供一套可以访问固态非易失性存储介质的通信协议(以sdio为接口),从产业化的角度看,这些存储介质一般集成在一个独立的外部模块中(卡、WIFI模组等),通过物理总线和mmc主机控制器、CPU连接。也就是说,WiFi模组也可以模拟为MMC设备。

看下sd卡内部图:图片转自:http://www.wowotech.net/basic_tech/mmc_sd_sdio_intro.html

【转】简单分析与移植rockchip平台mmc/sd卡_第2张图片

卡的内部由如下几个block组成

Memory core,存储介质,一般是NAND flash、NOR flash等;

Memory core interface,管理存储介质的接口,用于访问(读、写、擦出等操作)存储介质;

Card interface(CMD、CLK、DATA),总线接口,外界访问卡内部存储介质的接口,和具体的管脚相连;

Card interface controller,将总线接口上的协议转换为Memory core interface的形式,用于访问内部存储介质;

Power模块,提供reset、上电检测等功能;

寄存器(图中位于Card interface controller的左侧,那些小矩形),用于提供卡的信息、参数、访问控制等功能。


mmc框架在Linux之中体现为:图片转自:http://www.wowotech.net/basic_tech/mmc_sd_sdio_intro.html

【转】简单分析与移植rockchip平台mmc/sd卡_第3张图片

      对于sd卡这种存储设备来说,在Linux上被归类为块设备,sd卡块设备在Linux中被规划为card level <--> core level <--> host level。文件系统直接访问的是card level,card level通过请求队列来缓存(参考本人写的《编写一个ramdisk块设备驱动...》)。
      core level封装存储卡的识别、设置、挂载、读写通用api。
      host level则对应于主板上mmc卡控制器。  
      而card level、core level是由Linux社区维护的,我们不需要修改。只有host level才是我们关心的。host level和具体soc平台相关,soc原厂会提供可用的驱动源码配合相应设备树节点实现sd卡热插拔、读写操作。
也就是说,如果主板上的sd卡的sdio电路、卡检测电路、供电电路和原厂一致的话,我们需要做的是“配置内核、编译驱动“就可以实现任意sd卡的正常挂载、读写了。

card level:代码位于:drivers/mmc/card/

core level:代码位于:drivers/mmc/core/

host level:代码位于:drivers/mmc/host/rk_sdmmc.*、dw_mmc-rockchip.*


      所以,只要确保设备树配置正确,通常能正常操作sd卡,下面结合设备树说明文档将设备树相关节点走一遍,然后编译驱动加载到板端运行。附录有调试sd卡信息。

      参考文档:Documentation/devicetree/bindings下的rockchip-dw-mshc.txt、mmc.txt、mmc-card.txt、clock-bindings.txt、power_domain.txt。

      查找设备树时应该进到Documentation/devicetree/bindings/mmc下查找相关文档说明,比如rk平台下有rockchip-dw-mshc.txt,它告诉我们需要查找的compatible为:

      rockchip,rk3399-dw-mshc  位于rk3399.dtsi:308


   
   
   
   
  1. sdmmc: dwmmc@fe320000 {
  2. compatible = "rockchip,rk3399-dw-mshc",
  3. "rockchip,rk3288-dw-mshc";
  4. reg = < 0x0 0xfe320000 0x0 0x4000>; //由上一层在这里是根节点的#address-cells、#size-cells决定,很明显是支持rk soc的mmc卡控制器的寄存器信息。
  5. interrupts = 65 IRQ_TYPE_LEVEL_HIGH 0>; //mmc卡控制器的中断信息。
  6. max-frequency = < 150000000>; //由mmc.txt知道,这是供给mmc控制器的最大时钟
  7. assigned-clocks = <&cru HCLK_SD>; //时钟列表,&cru是一个phandle用来列出《cru: clock-controller@ff760000》时钟控制器提供的能力,
  8. //一般来说,需要 跟进一个assigned-clock-parents来使用,这里列表只有一个可忽略。参考附录
  9. assigned-clock-rates = < 200000000>; //设定的频率,需要和assigned-clocks一一对应,单位hz
  10. clocks = <&cru HCLK_SDMMC>, <&cru SCLK_SDMMC>, //列出时钟控制器phandle和时钟id对。其中时钟id来源于rk3399-cru.h
  11. <&cru SCLK_SDMMC_DRV>, <&cru SCLK_SDMMC_SAMPLE>;
  12. clock-names = "biu", "ciu", "ciu-drive", "ciu-sample"; //时钟对的名字
  13. fifo-depth = < 0x100>; //host层驱动和core层互传数据的缓存深度-256B
  14. power-domains = <&power RK3399_PD_SD>; //和时钟对类似,&power是一个phandle用来列出《power: power-controller》rk芯片提供的电源管理能力,
  15. //同样的电源id也来自于rk3399-power.h
  16. resets = <&cru SRST_SDMMC>; //软复位时钟,用来重置所有块设备(dw_mmc.c--dw_mci_probe函数中有调用)
  17. reset-names = "reset";
  18. status = "okay";
  19. };

 第一行的sdmmcdwmmc@fe320000的一个符号(label)其它节点引用sdmmc就相当于引用dwmmc@fe320000

      好的,我们分析下那些节点引用了sdmmc,可以grep &sdmmc查下。同时,给大家分享一个技巧:要是搜出来的文件很多不用怕。

      我们先按照文件名排除一些,然后打开arch\arm64\boot\dts\rockchip\.rk3399-sapphire-excavator-linux.dtb.dts.tmp因为我设备树是rk3399-sapphire-excavator-linux。搜下该文件名如:rk3399-sapphire.dtsi看能不能搜到。

引用sdmmc节点位于rk3399-sapphire.dtsi:565


   
   
   
   
  1. &sdmmc {
  2. clock-frequency = < 150000000>; //sd卡控制器的工作时钟大小
  3. clock-freq-min-max = < 100000 150000000>; //最大最小值
  4. supports-sd; //支持sd卡标记
  5. bus-width = < 4>; //sd卡总线(sdio)传输一个word的大小--4B
  6. cap-mmc-highspeed; //sd卡控制器支持mmc高速卡标记
  7. cap-sd-highspeed; //卡控制器支持sd高速卡标记
  8. disable-wp; //禁用写保护标记
  9. num-slots = < 1>; //在主板上接入sd卡控制器的sd卡卡槽数目
  10. //sd-uhs-sdr104;
  11. vqmmc-supply = <&vcc_sd>; //电源管理芯片(rk808)到sd卡控制器的电源regulator(可理解为可控通路)
  12. pinctrl-names = "default";
  13. pinctrl -0 = <&sdmmc_clk &sdmmc_cmd &sdmmc_cd &sdmmc_bus4>; //pinctrl是一个重要概念,用来指示这个节点引用了那些pin并且那些pin都具有什么功能。
  14. //在驱动代码中调用devm_pinctrl_get_select、pinctrl_select_state就可实现某组pin的复用设置。可理解为不同pinctrl对应不同方案。
  15. status = "okay";
  16. };

       到这里,我们发现设置了sd卡控制器的时钟、word widht、控制能力、电源管理。剩下就是我们最直接关系的sdio接口了,也就是sdmmc节点下的pinctrl-0方案。
老套路,搜索下。sdmmc节点下的pinctrl-0方案位于rk3399.dtsi文件中。

     再分享一个技巧,pinctrl规定了为 (0+n)_(A+m/8)(m%8);比如<1 9>极为gpio1_B1


   
   
   
   
  1. sdmmc_clk: sdmmc-clk {
  2. rockchip,pins =
  3. < 4 12 RK_FUNC_1 &pcfg_pull_none>; //gpio4_B3 复用为RK_FUNC_1(根据原理图可知为第一个复用) 默认开漏
  4. };
  5. sdmmc_cmd: sdmmc-cmd {
  6. rockchip,pins =
  7. < 4 13 RK_FUNC_1 &pcfg_pull_up>;
  8. };
  9. sdmmc_cd: sdmcc-cd {
  10. rockchip,pins =
  11. < 0 7 RK_FUNC_1 &pcfg_pull_up>;
  12. };
  13. sdmmc_bus4: sdmmc-bus4 {
  14. rockchip,pins =
  15. < 4 8 RK_FUNC_1 &pcfg_pull_up>, //gpio4_B0 复用为RK_FUNC_1(根据原理图可知为第一个复用) 默认上拉
  16. < 4 9 RK_FUNC_1 &pcfg_pull_up>, //gpio4_B1
  17. < 4 10 RK_FUNC_1 &pcfg_pull_up>, //gpio4_B2
  18. < 4 11 RK_FUNC_1 &pcfg_pull_up>; //gpio4_B3
  19. };

sd卡原理图:

【转】简单分析与移植rockchip平台mmc/sd卡_第4张图片

上面设备树节点描述和我的原理图是匹配的。


      好了,其实分析到这里sd卡就能用了,我们貌似没改过设备树,甚至驱动源码都没碰过就弄完了。大家不要觉得奇怪,我本身是一位汽车维修员。。(Linux fan)

      所以,我深知Linux底层的发展,为了更多东西模块化、标准化。在这种要求下Linux就会越来越结构化,可以改动的东西很少,绝大部分都由Linux社区那边的大佬维护。我们这些小白就看看代码理解理解代码就好了。
     不过,万一程序出问题了或者需要增强、适配一些功能,那么底层开发人员将要在纷繁复杂的源码中理代码,这是一件有挑战的工作。


附录:
 

时钟来源设置:参考clock-bindings.txt


   
   
   
   
  1. uart@a000 {
  2. ...
  3. clocks = <&osc 0>, <&pll 1>;
  4. clock-names = "baud", "register";
  5. assigned-clocks = <&clkcon 0>, <&pll 2>;
  6. assigned-clock-parents = <&pll 2>; //指定使用上面列表中的哪一个作为时钟来源
  7. assigned-clock-rates = < 0>, < 460800>; //设置时钟列表的时钟大小,单位hz
  8. };

调试sd卡

插卡打印:


   
   
   
   
  1. [ 82.959940] rockchip-iodomain ff770000.syscon:io-domains: Setting to 3300000 done //设置vcc电源为3.3v
  2. [ 82.960632] rockchip-iodomain ff770000.syscon:io-domains: Setting to 3300000 done
  3. [ 82.971961] mmc_host mmc0: Bus speed (slot 0) = 400000Hz (slot req 400000Hz, actual 400000HZ div = 0)
  4. [ 83.232097] mmc_host mmc0: Bus speed (slot 0) = 50000000Hz (slot req 50000000Hz, actual 50000000HZ div = 0)
  5. [ 83.233080] mmc0: new high speed SD card at address 211b //mmc控制器为刚插入的sd卡分配一个地址并告知sd卡,以后将用这个地址和sd卡通信。
  6. [ 83.235930] mmcblk0: mmc0: 211b APPSD 119 MiB
  7. [ 83.240962] mmcblk0: p1
  8. [ 83.521626] FAT-fs (mmcblk0p1): utf8 is not a recommended IO charset for FAT filesystems, filesystem will be case sensitive!
  9. [ 83.538985] FAT-fs (mmcblk0p1): Volume was not properly unmounted. Some data may be corrupt. Please run fsck.

拔卡打印:

[   76.957384] mmc0: card 211b removed
   
   
   
   

生成块设备节点:/dev/mmcblk0p1 

将sd卡挂载到/sdcard目录
# mkdir /run/sdcard
# mount /dev/mmcblk0p1  /run/sdcard/
# df -h
/dev/mmcblk0p1          118.7M      2.0K    118.7M   0% /run/sdcard

进入/run/sdcard/目录下
# echo 123 > 123.txt
取消挂载,再挂载。
# umount /run/sdcard/
# mount /dev/mmcblk0p1 /run/sdcard/
# cat sdcard/123.txt 

转自:简单分析与移植rockchip平台mmc/sd卡

你可能感兴趣的:(RK调试笔记)