Uboot中外存MMC(sd/iNand等)驱动架构代码简单分析

  • Post author:
  • Post category:其他


2020-7-5 19:50 北京 晴 屋内开空调不知道外面啥情况 一天没出屋 外面貌似闷热吧 !

本文仅作为技术积累,方便日后查阅!

作家格拉德威尔在《异类》一书中指出:“人们眼中的天才之所以卓越非凡,并非天资超人一等,而是付出了持续不断的努力。1万小时的锤炼是任何人从平凡变成超凡的必要条件”。他将此称为“一万小时定律”。要成为某个领域的专家,需要10000小时,按比例计算就是:如果每天工作八个小时,一周工作五天,那么成为一个领域的专家至少需要五年。

2.10.1.uboot与linux驱动

1、uboot本身是裸机程序

裸机程序中是直接操控硬件的,操作系统中必须通过驱动来操控硬件。这两个有什么区别?本质区别就是分层。

2、uboot的虚拟地址对硬件操作的影响

(1)操作系统(指的是linux)下MMU肯定是开启的,也就是说linux驱动中肯定都使用的是虚拟地址。而纯裸机程序中根本不会开MMU,全部使用的是物理地址。这是裸机下和驱动中操控硬件的一个重要区别。

(2)uboot早期也是纯物理地址工作的,但是现在的uboot开启了MMU做了虚拟地址映射,这个东西驱动也必须考虑。查uboot中的虚拟地址映射表,发现除了0x30000000-0x3FFFFFFF映射到了0xC0000000-0xCFFFFFFF之外,其余的虚拟地址空间全是原样映射的。而我们驱动中主要是操控硬件寄存器,而S5PV210的SFR都在0xExxxxxx地址空间,因此我们这里驱动中不必考虑虚拟地址。



这个虚拟地址映射详细原理和配置还不太懂,记录一下,有空专门去研究一下???????

3、uboot借用(移植)了linux驱动

(1)linux驱动非强耦合的模块化特点,是让uboot借用(移植)的关键。

(2)uboot移植了linux驱动源代码。

(3)uboot中的硬件驱动比linux简单。uboot移植linux驱动时只是借用了linux驱动的一部分而已。


2.10.2.iNand/SD驱动解析1

1、在uboot启动第二阶段start_armboot中初始化

mmc_initialize关键代码流程

start_armboot

mmc_initialize

cpu_mmc_init

setup_hsmmc_clock     SoC里的MMC控制器初始化(MMC系统时钟的初始化、SFR初始化)

setup_hsmmc_cfg_gpio  SoC里MMC相关的GPIO的初始化

smdk_s3c_hsmmc_init   SD卡/iNand芯片的初始化。

find_mmc_device

mmc_init

mmc_go_idle

mmc_send_if_cond

向sd卡发送各种指令………………………………………

关键数据结构

(1) mmc_initialize函数位于:uboot/drivers/mmc/mmc.c。

(2)

mmc_devices链表全局变量,用来记录系统中所有已经注册的SD/iNand设备



系统中对应一个SD卡/iNand设备都会用mmc结构体来抽象出对该设备各种信息的描述



每一个有效的mmc结构体最终都会向mmc_devices链表中插入对应的mmc结构来表示这个设备。mmc_initialize()中

(2) 基本大部分外设设备也遵循了类似MMC初始化类似的流程:


(各种外设都可以参照这个思路)




SoC里的MMC控制器初始化(MMC系统时钟的初始化、SFR初始化)、SoC里MMC相关的GPIO的初始化、SD卡/iNand芯片的初始化


(1) cpu_mmc_init函数位于:uboot/cpu/s5pc11x/cpu.c中。实质是通过调用3个函数来完成的。

(1)setup_hsmmc_clock,在uboot/cpu/s5pc11x/setup_hsmmc.c中。看名字函数是用来初始化SoC中MMC控制器中的时钟部分的。

(2)setup_hsmmc_cfg_gpio,在uboot/cpu/s5pc11x/setup_hsmmc.c中。看名字函数是用来配置SoC中MMC控制器相关的GPIO的。

smdk_s3c_hsmmc_init()函数位于:uboot/drivers/mmc/mmc.c。代码中首先函数内部通过宏定义USE_MMCx来判定是否调用s3c_hsmmc_initialize,总共支持4个通道,我们开发板目前总共仅外接的了两个,通道USE_MMC0接的iNand 通道USE_MMC2接的SD卡。两个都会调用s3c_hsmmc_initialize来初始化。之后调用static int

s3c_hsmmc_initialize

(int channel)对struct mmc 结构体进行赋值。在s3c_hsmmc.c中(各种对mmc的硬件操作都在这里)主要处理流程如下

在s3c_hsmmc_initialize中最后会调用mmc_register(struct mmc *mmc),mmc_register功能是进行mmc设备的注册,注册方法其实就是将当前这个struct mmc使用链表连接到mmc_devices这个全局变量中去,相当于全局的mmc管理链表中。

SD卡/iNand芯片的初始化结束。 返回到主mmc初始化流程中mmc_initialize()中通过find_mmc_device()找已经挂接上的mmc设备。find_mmc_device函数位于:drivers/mmc/mmc.c中。 遍历每一个mmc设备,比对编号查找已经挂载的mmc设备

找到设备后通过调用mmc_init,函数位于:drivers/mmc/mmc.c中。mmc_init函数内部就是依次通过向mmc卡发送命令码(CMD0、CMD2那些)来初始化SD卡/iNand内部的控制器,以达到初始化SD卡的目的。往下继续跟,实际调用到的是mmc中的回调函数。这些回调函数都是之前在s3c_hsmmc_initialize中注册过的,实际操作硬件函数在uboot/drivers/mmc/s3c_hsmmc.c

2.10.3.3、总结

(1)至此整个MMC系统初始化结束。

(2)整个MMC系统初始化分为2大部分:


(各种外设都可以参照这个思路)SoC这一端的MMC控制器的初始化



SD卡这一端卡本身的初始化


。前一步主要是在cpu_mmc_init函数中完成,后一部分主要是在mmc_init函数中完成。

(3)整个初始化完成后去使用sd卡/iNand时,操作方法和mmc_init函数中初始化SD卡的操作一样的方式。读写sd卡时也是通过总线向SD卡发送命令、读取/写入数据来完成的。

(4)顺着操作追下去,到了mmc_send_cmd函数处就断了,真正的向SD卡发送命令的硬件操作的函数找不到。之前注册的函数

(5)struct mmc结构体是关键。两部分初始化之间用mmc结构体来链接的,初始化完了后对mmc卡的常规读写操作也是通过mmc结构体来链接的。

2.10.4.iNand/SD驱动解析3

1、struct mmc

(1)驱动的设计中有一个关键数据结构。譬如MMC驱动的结构体就是struct mmc这些结构体中包含一些变量和一些函数指针,变量用来记录驱动相关的一些属性,函数指针用来记录驱动相关的操作方法。这些变量和函数指针加起来就构成了驱动。驱动就被抽象为这个结构体。

(2)一个驱动工作时主要就分几部分:


驱动构建(构建一个struct mmc然后填充它)





驱动运行时(调用这些函数指针指针的函数和变量)


2、分离思想

(1)分离思想就是说在驱动中将操作方法和数据分开。

(2)操作方法就是函数,数据就是变量。所谓操作方法和数据分离的意思就是:在不同的地方来存储和管理驱动的操作方法和变量,这样的优势就是驱动便于移植。



3、分层思想


(1)分层思想是指一个整个的驱动分为好多个层次。简单理解就是驱动分为很多个源文件,放在很多个文件夹中。譬如本课程讲的mmc的驱动涉及到drivers/mmc下面的2个文件和cpu/s5pc11x下的好几个文件。

(2)以mmc驱动为例来分析各个文件的作用:

uboot/drivers/mmc/mmc.c:本文件的主要内容是和MMC卡操作有关的方法,譬如MMC卡设置空闲状态的、卡读写数据等。但是本文件中并没有具体的硬件操作函数,操作最终指向的是struct mmc结构体中的函数指针,这些函数指针是在驱动构建的时候和真正硬件操作的函数挂接的(真正的硬件操作的函数在别的文件中)。

uboot/drivers/mmc/s3c_hsmmc.c:本文件中是SoC内部MMC控制器的硬件操作的方法,譬如向SD卡发送命令的函数(s3c_hsmmc_send_command),譬如和SD卡读写数据的函数(s3c_hsmmc_set_ios),这些函数就是具体操作硬件的函数,也就是mmc.c中需要的那些硬件操作函数。这些函数在mmc驱动初始化构建时(s3c_hsmmc_initialize函数中)和struct mmc挂接起来备用。

分析:mmc.c和s3c_hsmmc.c构成了一个分层,mmc.c中调用了s3c_hsmmc.中的函数,所以mmc.c在上层,s3c_hsmmc.c在下层。这两个分层后我们发现mmc.c中不涉及具体硬件的操作,s3c_hsmmc.c中不涉及驱动工程时的时序操作。因此移植的时候就有好处:譬如我们要把这一套mmc驱动移植到别的SoC上mmc.c就不用动,s3c_hsmmc.c动就可以了;譬如SoC没变但是SD卡升级了,这时候只需要更换mmc.c,不需要更换s3c_hsmmc.即可。

(3)cpu/s5pc11x/下面还有一个setup_hsmmc.c,也和MMC驱动有关。但是这些代码为什么不能放到drivers目录下去,而要放到cpu目录下去?因为这里面的2个函数(setup_hsmmc_clock和setup_hsmmc_cfg_gpio)都是和SoC有关的初始化函数,这两个函数不能放到drivers目录下去。实际上如果非把这两个函数放在uboot/drivers/mmc/s3c_hsmmc.c文件中也凑活能说过去。



版权声明:本文为qq_24373811原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。