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) < 0)
cpu_mmc_init(bis);   //时钟初始化  GPIO初始化,但是目前都是初始化SoC内部,并没有
              //涉及外部的SD卡的初始化
#if defined(DEBUG_S3C_HSMMC)
print_mmc_devices(',');
#endif
#ifdef CONFIG_CHECK_X210CV3
mmc = find_mmc_device(1);//lqm
#else
mmc = find_mmc_device(0);
#endif
if (mmc) {
err = mmc_init(mmc);
if (err)
err = mmc_init(mmc);
if (err) {
printf("Card init fail!\n");
return err;
}
}
printf("%ldMB\n", (mmc->capacity/(1024*1024/(1<<9))));
return 0;
}

    (1)INIT_LIST_HEAD(&mmc_devices);

内核链表的初始化函数,内核链表在初始化的时候,链表的next指针和prev指针都是指向其自身。mmc_devices链表全局变量,用来记录系统中所有已经注册的SD/iNand设备。所以向系统中插入一个SD卡/iNand设备,则系统驱动就会向mmc_devices链表中插入一个数据结构表示这个设备。

    (2)if (board_mmc_init(bis) < 0)

查看代码可知,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结构体来链接的。