UBOOT——MMC驱动分析


1:MMC驱动初始化是在start_armboot函数中

#if defined(CONFIG_X210)

    #if defined(CONFIG_GENERIC_MMC) puts ("SD/MMC: "); ///* //lqm masked
        mmc_exist = mmc_initialize(gd->bd); if (mmc_exist != 0) { puts ("0 MB\n"); } //*/
    #endif

    
    #if defined(CONFIG_CMD_NAND) puts("NAND: "); nand_init(); #endif

#endif /* CONFIG_X210 */
实际上是调用了 mmc_initialize(gd->bd);这个函数来进行初始化的
struct mmc *mmc;
这里定义了一个struct mmc类型的结构体指针;这个struct mmc类型的结构体非常重要,
我们说的驱动主要就是构建这个结构体;
在这个结构体中构建了一些列变量、函数指针等;这些变量记录了mmc的一些信息,函数指针所指向的函数是
用来向sd卡中发送命令、或者发送数据、直接操作最底层的特殊功能寄存器;
 1 struct mmc {  2     struct list_head link;  3     char name[32];  4     void *priv;  5     uint voltages;  6     uint version;  7     uint f_min;  8     uint f_max;  9     int high_capacity; 10     uint bus_width; 11     uint clock; 12     uint card_caps; 13     uint host_caps; 14     uint ocr; 15     uint scr[2]; 16     uint csd[4]; 17     uint cid[4]; 18     ushort rca; 19     uint tran_speed; 20     uint read_bl_len; 21     uint write_bl_len; 22  u32 capacity; 23     struct mmc_ext_csd    ext_csd;    /* mmc v4 extended card specific */
24  block_dev_desc_t block_dev; 25     int (*send_cmd)(struct mmc *mmc, 26             struct mmc_cmd *cmd, struct mmc_data *data); 27     void (*set_ios)(struct mmc *mmc); 28     int (*init)(struct mmc *mmc); 29 };
接下来就是cpu_mmc_init(bis);这个函数:
 1 int cpu_mmc_init(bd_t *bis)  2 {  3 #ifdef CONFIG_S3C_HSMMC  4  setup_hsmmc_clock();  5  setup_hsmmc_cfg_gpio();  6     return smdk_s3c_hsmmc_init();  7 #else
 8     return 0;  9 #endif
10 }
这个函数的作用是把mmc与Soc相关的初始化工作完成了;
mmc的初始化化分两个部分
  (1)与SoC有关的部分包括:初始化时钟、初始化相关GPIO、初始化与SoC有关的mmc控制器;
  (2)与外部sd卡有关的部分:初始化mmc卡中的芯片控制器等;
第一部分的mmc时钟初始化以及gpio初始化我们放在cpu_s5pc11x文件夹;
与SoC有关的控制器放在drivers/mmc文件夹下;
与mmc内部控制器有关的初始化函数为mmc_init,这个函数也在
drivers/mmc文件夹下;
上面几点表面:关于mmc的驱动是分离的,时钟、GPIO一部分;SoC内部控制器一部分;SoC外部控制器一部分;
这样做的一个好处就是减轻移植代码的大量工作;比如说mmc没有变,而更换了一个SoC,我们只需要更改SoC相关
的那一部分代码即可,同样SoC没有变而mmc卡变了,我们则只需要更改mmc卡相关的那部分初始化代码即可;
下面我们来详细看一下这些初始化函数
setup_hsmmc_clock:
选择时钟源、分频
 1 void setup_hsmmc_clock(void)  2 {  3  u32 tmp;  4  u32 clock;  5  u32 i;  6 
 7     /* MMC0 clock src = SCLKMPLL */
 8     tmp = CLK_SRC4_REG & ~(0x0000000f);  9     CLK_SRC4_REG = tmp | 0x00000006; 10 
11     /* MMC0 clock div */
12     tmp = CLK_DIV4_REG & ~(0x0000000f); 13     clock = get_MPLL_CLK()/1000000; 14     for(i=0; i<0xf; i++) 15  { 16         if((clock / (i+1)) <= 52) { 17             CLK_DIV4_REG = tmp | i<<0; 18             break; 19  } 20  } 21 
22 #ifdef USE_MMC1 23     /* MMC1 clock src = SCLKMPLL */
24     tmp = CLK_SRC4_REG & ~(0x000000f0); 25     CLK_SRC4_REG = tmp | 0x00000060; 26 
27     /* MMC1 clock div */
28     tmp = CLK_DIV4_REG & ~(0x000000f0); 29     CLK_DIV4_REG = tmp | i<<4; 30 #endif    
31 
32 #ifdef USE_MMC2 33     /* MMC2 clock src = SCLKMPLL */
34     tmp = CLK_SRC4_REG & ~(0x00000f00); 35     CLK_SRC4_REG = tmp | 0x00000600; 36 
37     /* MMC2 clock div */
38     tmp = CLK_DIV4_REG & ~(0x00000f00); 39     CLK_DIV4_REG = tmp | i<<8; 40 #endif
41 
42 #ifdef USE_MMC3 43     /* MMC3 clock src = SCLKMPLL */
44     tmp = CLK_SRC4_REG & ~(0x00000f00); 45     CLK_SRC4_REG = tmp | 0x00000600; 46 
47     /* MMC3 clock div */
48     tmp = CLK_DIV4_REG & ~(0x00000f00); 49     CLK_DIV4_REG = tmp | i<<12; 50 #endif    
51 }

setup_hsmmc_cfg_gpio:初始化相关GPIO可以对数据手册来看比较简单;

 1 void setup_hsmmc_cfg_gpio(void)  2 {  3     ulong reg;  4 
 5     /* MMC channel 0 */
 6     /* 7 pins will be assigned - GPG0[0:6] = CLK, CMD, CDn, DAT[0:3] */
 7     reg = readl(GPG0CON) & 0xf0000000;  8     writel(reg | 0x02222222, GPG0CON);  9     reg = readl(GPG0PUD) & 0xffffc000; 10     writel(reg | 0x00002aaa, GPG0PUD); 11     writel(0x00003fff, GPG0DRV); 12 #ifdef USE_MMC0_8BIT 13     reg = readl(GPG1CON) & 0xf0000fff; 14     writel(reg | 0x03333000, GPG1CON); 15     reg = readl(GPG1PUD) & 0xffffc03f; 16     writel(reg | 0x00002a80, GPG1PUD); 17     writel(0x00003fc0, GPG1DRV); 18 #endif
19 
20 #ifdef USE_MMC1 21     /* MMC channel 1 */
22     /* 7 pins will be assigned - GPG1[0:6] = CLK, CMD, CDn, DAT[0:3] */
23     reg = readl(GPG1CON) & 0xf0000000; 24     writel(reg | 0x02222222, GPG1CON); 25     reg = readl(GPG1PUD) & 0xffffc000; 26     writel(reg | 0x00002aaa, GPG1PUD); 27     writel(0x00003fff, GPG1DRV); 28 #endif
29 
30 #ifdef USE_MMC2 31     /* MMC channel 2 */
32     /* 7 pins will be assigned - GPG2[0:6] = CLK, CMD, CDn, DAT[0:3] */
33     reg = readl(GPG2CON) & 0xf0000000; 34     writel(reg | 0x02222222, GPG2CON); 35     reg = readl(GPG2PUD) & 0xffffc000; 36     writel(reg | 0x00002aaa, GPG2PUD); 37     writel(0x00003fff, GPG2DRV); 38 #ifdef USE_MMC2_8BIT 39     /* 4 pins will be assigned - GPG3[3:6] = DAT[4:7] */
40     reg = readl(GPG3CON) & 0xf0000fff; 41     writel(reg | 0x03333000, GPG3CON); 42     reg = readl(GPG3PUD) & 0xffffc03f; 43     writel(reg | 0x00002a80, GPG3PUD); 44     writel(0x00003fc0, GPG3DRV); 45 #endif
46 #endif
47 
48 #ifdef USE_MMC3 49     /* MMC channel 3 */
50     /* 7 pins will be assigned - GPG0[0:6] = CLK, CMD, CDn, DAT[0:3] */
51     reg = readl(GPG3CON) & 0xf0000000; 52     writel(reg | 0x02222222, GPG3CON); 53     reg = readl(GPG3PUD) & 0xffffc000; 54     writel(reg | 0x00002aaa, GPG3PUD); 55     writel(0x00003fff, GPG3DRV); 56 #endif
57 }
 

下面来看一下smdk_s3c_hsmmc_init函数

这个函数实际是调用的s3c_hsmmc_initialize 这个函数 

 
int smdk_s3c_hsmmc_init(void) {     int err; #ifdef USE_MMC0 err = s3c_hsmmc_initialize(0); if(err) return err; #endif #ifdef USE_MMC1 err = s3c_hsmmc_initialize(1); if(err) return err; #endif     #ifdef USE_MMC2 err = s3c_hsmmc_initialize(2); if(err) return err; #endif     #ifdef USE_MMC3 err = s3c_hsmmc_initialize(3); if(err) return err; #endif
    return -1; }
 

s3c_hsmmc_initialize 这个函数是对SoC中mmc控制器的初始化:在这个函数中主要是把我们最早定义的struct mmc中的变量以及函数指针进行了初始化;

而真正的操作寄存器的函数是

s3c_hsmmc_send_command

s3c_hsmmc_set_ios

s3c_hsmmc_init

发送命令 发送数据 初始化三个函数,这三个函数是最底层的直接操作GPIO、特殊功能寄存器的函数;

而这三个函数以及一些变量被封装在struct mmc结构体中,我们操作系统对mmc设备进行操作的时候,只到封装以后的这个结构体中进行操作即可;

 1 static int s3c_hsmmc_initialize(int channel)  2 {  3     struct mmc *mmc;  4 
 5     mmc = &mmc_channel[channel];  6 // printf("sdcard channel: %\n", channel);
 7     sprintf(mmc->name, "S3C_HSMMC%d", channel);  8     mmc->priv = &mmc_host[channel];  9     mmc->send_cmd = s3c_hsmmc_send_command; 10     mmc->set_ios = s3c_hsmmc_set_ios; 11     mmc->init = s3c_hsmmc_init; 12 //yan
13     mmc->voltages = MMC_VDD_32_33 | MMC_VDD_33_34; 14     mmc->host_caps = MMC_MODE_4BIT | MMC_MODE_HS_52MHz | MMC_MODE_HS; 15 #if defined(USE_MMC0_8BIT) || defined(USE_MMC2_8BIT)
16     mmc->host_caps |= MMC_MODE_8BIT; 17 #endif
18 
19     mmc->f_min = 400000; 20 // mmc->f_max = 26000000;//52000000;
21     mmc->f_max = 52000000; 22 
23     mmc_host[channel].clock = 0; 24 
25     switch(channel) { 26     case 0: 27         mmc_host[channel].ioaddr = (void *)ELFIN_HSMMC_0_BASE; 28         break; 29     case 1: 30         mmc_host[channel].ioaddr = (void *)ELFIN_HSMMC_1_BASE; 31         break; 32     case 2: 33         mmc_host[channel].ioaddr = (void *)ELFIN_HSMMC_2_BASE; 34         break; 35 #ifdef USE_MMC3 36     case 3: 37         mmc_host[channel].ioaddr = (void *)ELFIN_HSMMC_3_BASE; 38         break; 39 #endif
40     default: 41         printk("mmc err: not supported channel %d\n", channel); 42  } 43     
44     return mmc_register(mmc);

 

 

最后我们看一下mmc_init这个函数 这个代码中是调用了struct mmc 中的函数进行了一些时序操作

 1 int mmc_init(struct mmc *host)  2 {  3     int err;  4 
 5     err = host->init(host);  6 
 7     if (err)  8         return err;  9 
10     /* Reset the Card */
11     err = mmc_go_idle(host); 12 
13     if (err) 14         return err; 15 
16     /* Test for SD version 2 */
17     err = mmc_send_if_cond(host); 18 
19     /* Now try to get the SD card's operating condition */
20     err = mmc_send_app_op_cond(host); 21 
22     /* If the command timed out, we check for an MMC card */
23     if (err == TIMEOUT) { 24         err = mmc_send_op_cond(host); 25 
26         if (err) 27             return UNUSABLE_ERR; 28     } else
29         if (err) 30             return UNUSABLE_ERR; 31 
32     return mmc_startup(host); 33 }

 


  









免责声明!

本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系本站邮箱yoyou2525@163.com删除。



 
粤ICP备18138465号  © 2018-2025 CODEPRJ.COM