uboot移植之uboot中的SD卡驱动解析
1:地址对硬件操作的影响
(1)操作系统(指的是linux)下MMU肯定是开启的,也就是说linux驱动中肯定都使用的是虚拟地址。而纯裸机程序中根本不会开MMU,全部使用的是物理地址。这是裸机下和驱动中操控硬件的一个重要区别。
(2)uboot早期也是纯物理地址工作的,但是现在的uboot开启了MMU做了虚拟地址映射,这个东西驱动也必须考虑。查uboot中的虚拟地址映射表,发现210开发板里面,除了0x30000000-0x3FFFFFFF映射到了0xC0000000-0xCFFFFFFF之外,其余的虚拟地址空间全是原样映射的。而我们驱动中主要是操控硬件寄存器,而S5PV210的SFR都在0xExxxxxx地址空间,因此驱动中不必考虑虚拟地址。
2:从start_armboot开始
这里的();就是SD卡的初始化函数,这个函数的作用就是初始化开发板上MMC系统。MMC系统的初始化应该包含这么几部分:SoC里的MMC控制器初始化
(MMC系统时钟的初始化、SFR初始化)、SoC里MMC相关的GPIO的初始化、SD卡/iNand芯片的初始化。
3:mmc_initialize()函数分析
int mmc_initialize(bd_t *bis)
{
struct mmc *mmc;
int err;
INIT_LIST_HEAD(&mmc_devices); //初始化内核链表,next指针和prev指针都指向自身
cur_dev_num = 0;// SD 卡的插槽,我们这里有4个插槽
if (board_mmc_init(bis) capacity/(1024*1024/(1
(1)INIT_LIST_HEAD(&mmc_devices);
内核链表的初始化函数,内核链表在初始化的时候,链表的next指针和prev指针都是指向其自身。mmc_devices链表全局变量,用来记录系统中所有已经注册的SD/iNand设备。所以向系统中插入一个SD卡/iNand设备,则系统驱动就会向mmc_devices链表中插入一个数据结构表示这个设备。
(2)if (board_mmc_init(bis)
查看代码可知,board_mmc_init(),其实是__def_mmc_init()函数的别名,而__def_mmc_init()函数的返回值固定是-1,所以if判断成立,执行cpu_mmc_init()函数。
(3)cpu_mmc_init()函数
cpu_mmc_init()函数在uboot/cpu/s5pc11x/cpu.c中,
int cpu_mmc_init(bd_t *bis)
{
#ifdef CONFIG_S3C_HSMMC
setup_hsmmc_clock();
setup_hsmmc_cfg_gpio();
return smdk_s3c_hsmmc_init();
#else
return 0;
#endif
}
setup_hsmmc_clock():在uboot/cpu/s5pc11x/setup_hsmmc.c中。hsmmc高速mmc,clock时钟,所以这个函数应该是用于mmc控制器的时钟初始化。里面是通过宏定义来选择配置哪些通道的时钟(通过MPLL分频得到)。x210选择的是通道0和通道2(SD卡)
setup_hsmmc_cfg_gpio():MMC控制器IO引脚的设置。在在uboot/cpu/s5pc11x/setup_hsmmc.c中中
smdk_s3c_hsmmc_init():uboot/drivers/mmc/s3c_hsmmc.c中。该函数里面主要调用s3c_hsmmc_initialize(int channel)函数,参数channel表示的是MMC的通道。
至此,cpu_mmc_init()函数分析结束,继续分析mmc_initialize()函数。
(4) find_mmc_device(0)函数
find_mmc_device()uboot/drivers/mmc/mmc.c中,这个函数其实就是通过mmc设备编号来在系统中查找对应的mmc设备(struct mmc的对象,根据上面分析系统中有2个,编号分别是0和2)。函数工作原理就是通过遍历mmc_devices链表,去依次寻找系统中注册的mmc设备,然后对比其设备编号和我们当前要查找的设备编号,如果相同则就找到了要找的设备。找到了后调用mmc_init函数来初始化它。
(5)mmc_init()函数
mmc_init()函数在drivers/mmc/mmc.c中。这个函数的主要作用是进行mmc卡的初始化。mmc_init函数内部就是依次通过向mmc卡发送命令码(CMD0、CMD2那些)来初始化SD卡/iNand内部的控制器,以达到初始化SD卡的目的。
4:总结
(1)整个MMC系统初始化分为2大部分:SoC这一端的MMC控制器的初始化,SD卡这一端卡本身的初始化。前一步主要是在cpu_mmc_init函数中完成,后一部分主要是在mmc_init函数中完成。
(2)整个初始化完成后去使用sd卡/iNand时,操作方法和mmc_init函数中初始化SD卡的操作一样的方式。读写sd卡时也是通过总线向SD卡发送命令、读取/写入数据来完成的。
(3)struct mmc结构体是关键。两部分初始化之间用mmc结构体来链接的,初始化完了后对mmc卡的常规读写操作也是通过mmc结构体来链接的。
1:地址对硬件操作的影响
(1)操作系统(指的是linux)下MMU肯定是开启的,也就是说linux驱动中肯定都使用的是虚拟地址。而纯裸机程序中根本不会开MMU,全部使用的是物理地址。这是裸机下和驱动中操控硬件的一个重要区别。
(2)uboot早期也是纯物理地址工作的,但是现在的uboot开启了MMU做了虚拟地址映射,这个东西驱动也必须考虑。查uboot中的虚拟地址映射表,发现210开发板里面,除了0x30000000-0x3FFFFFFF映射到了0xC0000000-0xCFFFFFFF之外,其余的虚拟地址空间全是原样映射的。而我们驱动中主要是操控硬件寄存器,而S5PV210的SFR都在0xExxxxxx地址空间,因此驱动中不必考虑虚拟地址。
2:从start_armboot开始
这里的();就是SD卡的初始化函数,这个函数的作用就是初始化开发板上MMC系统。MMC系统的初始化应该包含这么几部分:SoC里的MMC控制器初始化
(MMC系统时钟的初始化、SFR初始化)、SoC里MMC相关的GPIO的初始化、SD卡/iNand芯片的初始化。
3:mmc_initialize()函数分析 无奈人生安全网
int mmc_initialize(bd_t *bis)
{
struct mmc *mmc;
int err;
INIT_LIST_HEAD(&mmc_devices); //初始化内核链表,next指针和prev指针都指向自身
cur_dev_num = 0;// SD 卡的插槽,我们这里有4个插槽
if (board_mmc_init(bis) capacity/(1024*1024/(1
(1)INIT_LIST_HEAD(&mmc_devices);
内核链表的初始化函数,内核链表在初始化的时候,链表的next指针和prev指针都是指向其自身。mmc_devices链表全局变量,用来记录系统中所有已经注册的SD/iNand设备。所以向系统中插入一个SD卡/iNand设备,则系统驱动就会向mmc_devices链表中插入一个数据结构表示这个设备。
(2)if (board_mmc_init(bis)
查看代码可知,board_mmc_init(),其实是__def_mmc_init()函数的别名,而__def_mmc_init()函数的返回值固定是-1,所以if判断成立,执行cpu_mmc_init()函数。
(3)cpu_mmc_init()函数
cpu_mmc_init()函数在uboot/cpu/s5pc11x/cpu.c中,
int cpu_mmc_init(bd_t *bis)
{
#ifdef CONFIG_S3C_HSMMC
setup_hsmmc_clock();
setup_hsmmc_cfg_gpio();
copyright 无奈人生
return smdk_s3c_hsmmc_init();
#else
return 0;
#endif
}
setup_hsmmc_clock():在uboot/cpu/s5pc11x/setup_hsmmc.c中。hsmmc高速mmc,clock时钟,所以这个函数应该是用于mmc控制器的时钟初始化。里面是通过宏定义来选择配置哪些通道的时钟(通过MPLL分频得到)。x210选择的是通道0和通道2(SD卡)
setup_hsmmc_cfg_gpio():MMC控制器IO引脚的设置。在在uboot/cpu/s5pc11x/setup_hsmmc.c中中
smdk_s3c_hsmmc_init():uboot/drivers/mmc/s3c_hsmmc.c中。该函数里面主要调用s3c_hsmmc_initialize(int channel)函数,参数channel表示的是MMC的通道。
至此,cpu_mmc_init()函数分析结束,继续分析mmc_initialize()函数。
(4) find_mmc_device(0)函数
find_mmc_device()uboot/drivers/mmc/mmc.c中,这个函数其实就是通过mmc设备编号来在系统中查找对应的mmc设备(struct mmc的对象,根据上面分析系统中有2个,编号分别是0和2)。函数工作原理就是通过遍历mmc_devices链表,去依次寻找系统中注册的mmc设备,然后对比其设备编号和我们当前要查找的设备编号,如果相同则就找到了要找的设备。找到了后调用mmc_init函数来初始化它。 www.wnhack.com
(5)mmc_init()函数
mmc_init()函数在drivers/mmc/mmc.c中。这个函数的主要作用是进行mmc卡的初始化。mmc_init函数内部就是依次通过向mmc卡发送命令码(CMD0、CMD2那些)来初始化SD卡/iNand内部的控制器,以达到初始化SD卡的目的。
4:总结
(1)整个MMC系统初始化分为2大部分:SoC这一端的MMC控制器的初始化,SD卡这一端卡本身的初始化。前一步主要是在cpu_mmc_init函数中完成,后一部分主要是在mmc_init函数中完成。
(2)整个初始化完成后去使用sd卡/iNand时,操作方法和mmc_init函数中初始化SD卡的操作一样的方式。读写sd卡时也是通过总线向SD卡发送命令、读取/写入数据来完成的。
(3)struct mmc结构体是关键。两部分初始化之间用mmc结构体来链接的,初始化完了后对mmc卡的常规读写操作也是通过mmc结构体来链接的。
内容来自无奈安全网