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
");
}
//*/
#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: % ", 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 ", 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 }