1.首先分析 sd/mmc 初始化: // board.c puts ("SD/MMC: "); mmc_exist = mmc_initialize(gd->bd); /////////////////////////////////////////////////////////////////////////////////////////////////////////// int mmc_initialize(bd_t *bis) { struct mmc *mmc; int err; //初始化一个双链表结构体变量。 INIT_LIST_HEAD(&mmc_devices); //当前设备节点,还没放入到mmc结构中 cur_dev_num = 0; if (board_mmc_init(bis) < 0) cpu_mmc_init(bis); //--------------------------------------------------------------------- /* int cpu_mmc_init(bd_t *bis) { #ifdef CONFIG_S3C_HSMMC setup_hsmmc_clock(); //配置mmc0~mmc3的时钟源 setup_hsmmc_cfg_gpio(); return smdk_s3c_hsmmc_init(); #else return 0; #endif } */ --------- void setup_hsmmc_clock(void) { u32 tmp; u32 clock; u32 i; /* MMC0 clock src = SCLKMPLL */ tmp = CLK_SRC4_REG & ~(0x0000000f); CLK_SRC4_REG = tmp | 0x00000006; /* MMC0 clock div */ tmp = CLK_DIV4_REG & ~(0x0000000f); //根据时钟变化,同步SD卡的时钟。 clock = get_MPLL_CLK()/1000000; for(i=0; i<0xf; i++) { if((clock / (i+1)) <= 50) { CLK_DIV4_REG = tmp | i<<0; break; } } //同时也初始化ch2通道的时钟。 #ifdef USE_MMC2 /* MMC2 clock src = SCLKMPLL */ tmp = CLK_SRC4_REG & ~(0x00000f00); CLK_SRC4_REG = tmp | 0x00000600; /* MMC2 clock div */ tmp = CLK_DIV4_REG & ~(0x00000f00); CLK_DIV4_REG = tmp | i<<8; #endif */ ------------------------------ //接着设置mmc gpio口的方向 void setup_hsmmc_cfg_gpio(void) { ulong reg; //GPG0 就是一个通道0的接口定义 /* MMC channel 0 */ /* 7 pins will be assigned - GPG0[0:6] = CLK, CMD, CDn, DAT[0:3] */ reg = readl(GPG0CON) & 0xf0000000; //设置为SD接口模式,定义了4bitdata。cmd clk ,cd writel(reg | 0x02222222, GPG0CON); reg = readl(GPG0PUD) & 0xffffc000; //上啦使能,硬件io口需要强制上拉 writel(reg | 0x00002aaa, GPG0PUD); writel(0x00003fff, GPG0DRV); #ifdef USE_MMC2 /* MMC channel 2 */ /* 7 pins will be assigned - GPG2[0:6] = CLK, CMD, CDn, DAT[0:3] */ reg = readl(GPG2CON) & 0xf0000000; writel(reg | 0x02222222, GPG2CON); reg = readl(GPG2PUD) & 0xffffc000; writel(reg | 0x00002aaa, GPG2PUD); writel(0x00003fff, GPG2DRV); */ -----------------------------
int smdk_s3c_hsmmc_init(void) { #ifdef USE_MMC0 //emmc err = s3c_hsmmc_initialize(0); #endif #ifdef USE_MMC2 //sd err = s3c_hsmmc_initialize(2); #endif
static int s3c_hsmmc_initialize(int channel) { struct mmc *mmc; //定义了4个通道结构体 mmc = &mmc_channel[channel]; //名称分别是s3c_hsmmc0~3 sprintf(mmc->name, "S3C_HSMMC%d", channel); //获取host mmc->priv = &mmc_host[channel]; //命令函数 mmc->send_cmd = s3c_hsmmc_send_command; //通过core层传递过来的参数,配置host寄存器(时钟,总线宽度等) mmc->set_ios = s3c_hsmmc_set_ios; //------------------------------> mmc->init = s3c_hsmmc_init; //------------------------------------> //mmc工作电压范围 mmc->voltages = MMC_VDD_32_33 | MMC_VDD_33_34; //mmc总线4bit模式,clk 52Hz。 hs模式 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; //系统物理DMA地址 switch(channel) { case 0: mmc_host[channel].ioaddr = (void *)ELFIN_HSMMC_0_BASE; break; case 2: mmc_host[channel].ioaddr = (void *)ELFIN_HSMMC_2_BASE; break; default: printk("mmc err: not supported channel %d\n", channel); } return mmc_register(mmc); } //把mmc这个设备放入链表中 int mmc_register(struct mmc *mmc) { /* Setup the universal parts of the block interface just once */ mmc->block_dev.if_type = IF_TYPE_MMC; //注意这里,分配当前mmc节点为 cur_dev_num ,第一个位 0,第2个位1。 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); return 0; } static int s3c_hsmmc_init(struct mmc *mmc) { struct sdhci_host *host = (struct sdhci_host *)mmc->priv; //重设host时钟为0, sdhci_reset(host, SDHCI_RESET_ALL); host->version = readw(host->ioaddr + SDHCI_HOST_VERSION); sdhci_init(host); sdhci_change_clock(host, 400000); return 0; } 时钟全部初始化完成,返回
=============================================== //根据节点 0 找到mmc的结构 这里为什么是只定义0,是因为,当宏定义打开通道2时 //,设备只有一个,mmc->block_dev.dev =0++;所以找链表时,就是0 了。 //定义了4个通道结构体 mmc = &mmc_channel[2]; //如果定义 0 和2, 则会mmc = &mmc_channel[0] mmc = &mmc_channel[2], //然后一个一个放入链表,dev+1,找通道2时,必须改 find_mmc_device(1); mmc = find_mmc_device(0); -------------------------------------------
struct mmc *find_mmc_device(int dev_num) { struct mmc *m; struct list_head *entry; list_for_each(entry, &mmc_devices) { m = list_entry(entry, struct mmc, link); //根据节点,来获取mmc结构 if (m->block_dev.dev == dev_num) return m; } printf("MMC Device %d not found\n", dev_num); return NULL; } ==================================== //获取mmc结构后,开始进入mmc_init if (mmc) { err = mmc_init(mmc); 至此对sd/mmc初始化部分分析完成。 ====================================================
修改: 以前是从NAND flash启动,现在是从emmc启动,修改启动模式: /include/configs/smdkv210signle.h //#define CFG_FASTBOOT_NANDBSP //关闭 nand flash启动模式 #define CFG_FASTBOOT_SDMMCBSP //打开 sd/mmc启动模式 #define USE_MMC0 //支持 emmc (占用了通道0) #define USE_MMC2 //支持sd (占用了通道2) 修改 /drivers/mmc/mmc.c 使它支持 emmc 和sd int mmc_initialize(bd_t *bis) { struct mmc *mmc; int err; INIT_LIST_HEAD(&mmc_devices); cur_dev_num = 0; if (board_mmc_init(bis) < 0) cpu_mmc_init(bis); #if defined(DEBUG_S3C_HSMMC) print_mmc_devices(','); #endif #if ( defined(USE_MMC0 ) && defined(USE_MMC2 ) ) //emmc mmc = find_mmc_device(0); if (mmc) { err = mmc_init(mmc); if (err) err = mmc_init(mmc); if (err) { printf("Card init fail!\n"); return err; } } printf("emmc %ldMB\n", (mmc->capacity/(1024*1024/(mmc->read_bl_len)))); //sd mmc = find_mmc_device(1); if (mmc) { err = mmc_init(mmc); if (err) err = mmc_init(mmc); if (err) { printf("Card init fail!\n"); return err; } } printf(" sd %ldMB\n", (mmc->capacity/(1024*1024/((mmc->read_bl_len))))); return 0; } #else mmc = find_mmc_device(0); 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/(mmc->read_bl_len)))); return 0; #endif mmc->read_bl_len :这里要说下此变量,这是emmc 里CSD[80]所定义的,指明了此emmc的块大小,对于SD卡分区格式来说,只支持512 bety 块大小。如果 mmc->read_bl_len =1024 的话,对于整个分区体系来说是不支持的,会造成分区不完全。所以后续代码需要修改。 ----------------------------------------------------------------------