uboot的eMMC初始化代码流程分析

来源:互联网 发布:泰迪罗宾地位知乎 编辑:程序博客网 时间:2024/05/17 08:08

源码参考九鼎科技移植的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中,包括卡的具体状态机流程,将另起一编进行分析