源码参考九鼎科技移植的X210开发板捆绑BSP中的uboot, 版本为1.3.4
mmc初始化函数int mmc_initialize(bd_t *bis)在uboot/lib_arm/board.c中的start_armboot()函数中被调用(uboot的C语言阶段)
puts ("SD/MMC: ");
mmc_exist = mmc_initialize(gd->bd);
1. 函数本体在uboot/mmc/mmc.c中
INIT_LIST_HEAD(&mmc_devices);
cur_dev_num = 0;
mmc_devices是一个mmc.c中定义的内核链表类型的全局变量
struct list_head {
struct list_head *next, *prev;
};
static struct list_head mmc_devices;
INIT_LIST_HEAD初始化mmc_devices, 将next, prev都指向自己,表示目前没有已注册的mmc设备, cur_dev_num被相应初始化为0
#define INIT_LIST_HEAD(ptr) do { \
(ptr)->next = (ptr); (ptr)->prev = (ptr); \
} while (0)
cpu_mmc_init(bd_t *bis)函数中调用了三个初始化函数,函数定义在uboot/cpu/s5pc11x/cpu.c中
setup_hsmmc_clock();
setup_hsmmc_cfg_gpio();
smdk_s3c_hsmmc_init();
setup_hsmmc_clock()的定义在uboot/cpu/s5pc11x/setup_hsmmc.c中, 设置MMC通道0和通道2的clock source为SCLKMPLL(寄存器CLK_SRC4), 设置分频系数(寄存器CLK_DIV4)使得给MMC的时钟频率小于50Mhz
setup_hsmmc_cfg_gpio()的定义也在uboot/cpu/s5pc11x/setup_hsmmc.c中, 设置MMC通道0和通道2相应的GPIO为mmc模式,MMC0对应GPG0, MMC2对应GPG2,主要设置寄存器GPG0CON, GPG0PUD, GPG2CON, GPG2PUD
smdk_s3c_hsmmc_init()的定义在uboot/drivers/mmc/s3c_hsmmc.c中,其中对通道0和通道2分别调用了s3c_hsmmc_initialize(), 函数定义也在uboot/drivers/mmc/s3c_hsmmc.c中
static int s3c_hsmmc_initialize(int channel)
mmc设置维护在mmc_channel[]这个结构体数组中,每次调用s3c_hsmmc_initialize(x)就是对特定通道的mmc设备进行初始化的过程
struct mmc mmc_channel[MMC_MAX_CHANNEL];
mmc = &mmc_channel[channel];
mmc设备初始化的过程包括以下内容,主要是填充了mmc_host[x]和mmc_channel[x]两个结构体
a. mmc->name赋值
sprintf(mmc->name, "S3C_HSMMC%d", channel);
b. mmc->priv赋值,mmc_host[]是uboot/drivers/mmc/s3c_hsmmc.c中定义的一个结构体数组
mmc->priv = &mmc_host[channel];
struct sdhci_host mmc_host[MMC_MAX_CHANNEL];
c. 其它赋值
mmc->send_cmd = s3c_hsmmc_send_command;
mmc->set_ios = s3c_hsmmc_set_ios;
mmc->init = s3c_hsmmc_init;
mmc->voltages = MMC_VDD_32_33 | MMC_VDD_33_34;
mmc->host_caps = MMC_MODE_4BIT | MMC_MODE_HS_52MHz | MMC_MODE_HS;
#if defined(USE_MMC0_8BIT) || defined(USE_MMC2_8BIT)
mmc->host_caps |= MMC_MODE_8BIT;
#endif
mmc->f_min = 400000;
mmc->f_max = 52000000;
mmc_host[channel].clock = 0;
d. 绑定mmc_host[x]与S5PV210对应mmc通道的寄存器地址, SDMA System Address register (Channel X)
mmc_host[channel].ioaddr = (void *)ELFIN_HSMMC_X_BASE;
c. 最后调用int mmc_register(struct mmc *mmc)进行注册, 函数定义在uboot/drivers/mmc/mmc.c中, 注册内容也是填充mmc_channel[x]结构体, 包括把这个结构体内嵌的内核链表初始化并加入到mmc_devices链表的尾端
mmc->block_dev.if_type = IF_TYPE_MMC;
mmc->block_dev.dev = cur_dev_num++;
mmc->block_dev.removable = 1;
mmc->block_dev.block_read = mmc_bread;
mmc->block_dev.block_write = mmc_bwrite;
INIT_LIST_HEAD(&mmc->link);
list_add_tail(&mmc->link, &mmc_devices);
struct mmc *find_mmc_device(int dev_num)函数定义在uboot/drivers/mmc/mmc.c中, 用于在mmc_devices查到到已经注册的mmc device结构体
mmc = find_mmc_device(0);
如果找到的话, 进行card初始化操作(retry一次)
err = mmc_init(mmc);
int mmc_init(struct mmc *host)函数定义在uboot/drivers/mmc/mmc.c中,包括卡的具体状态机流程,将另起一编进行分析