简单分析与移植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

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

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

卡的内部由如下几个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

      对于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

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

 第一行的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

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

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

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

sdmmc_clk: sdmmc-clk {
	rockchip,pins =
	<4 12 RK_FUNC_1 &pcfg_pull_none>;//gpio4_B3 复用为RK_FUNC_1(根据原理图可知为第一个复用) 默认开漏
};

sdmmc_cmd: sdmmc-cmd {
	rockchip,pins =
	<4 13 RK_FUNC_1 &pcfg_pull_up>;
};

sdmmc_cd: sdmcc-cd {
	rockchip,pins =
	<0 7 RK_FUNC_1 &pcfg_pull_up>;
};

sdmmc_bus4: sdmmc-bus4 {
	rockchip,pins =
	<4 8 RK_FUNC_1 &pcfg_pull_up>,  //gpio4_B0 复用为RK_FUNC_1(根据原理图可知为第一个复用) 默认上拉
	<4 9 RK_FUNC_1 &pcfg_pull_up>, //gpio4_B1
	<4 10 RK_FUNC_1 &pcfg_pull_up>, //gpio4_B2
	<4 11 RK_FUNC_1 &pcfg_pull_up>; //gpio4_B3
};

sd卡原理图:

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


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

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


附录:
 

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

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

调试sd卡

插卡打印:

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

  • 4
    点赞
  • 52
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值