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 }