android系统移植emmc记录(3)--sd/mmc初始化 .

  1. 1.首先分析 sd/mmc 初始化:  
  2.  // board.c   
  3. puts ("SD/MMC:  ");  
  4. mmc_exist = mmc_initialize(gd->bd);  
  5. ///////////////////////////////////////////////////////////////////////////////////////////////////////////   
  6. int mmc_initialize(bd_t *bis)  
  7. {  
  8.     struct mmc *mmc;  
  9.     int err;  
  10.     //初始化一个双链表结构体变量。   
  11.     INIT_LIST_HEAD(&mmc_devices);  
  12.     //当前设备节点,还没放入到mmc结构中   
  13.     cur_dev_num = 0;  
  14.       
  15.     if (board_mmc_init(bis) < 0)  
  16.         cpu_mmc_init(bis);  
  17. //---------------------------------------------------------------------   
  18. /*       
  19. int cpu_mmc_init(bd_t *bis) 
  20. { 
  21. #ifdef CONFIG_S3C_HSMMC 
  22.     setup_hsmmc_clock();  //配置mmc0~mmc3的时钟源 
  23.     setup_hsmmc_cfg_gpio(); 
  24.     return smdk_s3c_hsmmc_init(); 
  25. #else 
  26.     return 0; 
  27. #endif 
  28. } 
  29. */  
  30. ---------  
  31. void setup_hsmmc_clock(void)  
  32. {  
  33.     u32 tmp;  
  34.     u32 clock;  
  35.     u32 i;  
  36.   
  37.     /* MMC0 clock src = SCLKMPLL */  
  38.     tmp = CLK_SRC4_REG & ~(0x0000000f);  
  39.     CLK_SRC4_REG = tmp | 0x00000006;  
  40.     /* MMC0 clock div */  
  41.     tmp = CLK_DIV4_REG & ~(0x0000000f);  
  42.     //根据时钟变化,同步SD卡的时钟。   
  43.     clock = get_MPLL_CLK()/1000000;  
  44.     for(i=0; i<0xf; i++)  
  45.     {  
  46.         if((clock / (i+1)) <= 50) {  
  47.             CLK_DIV4_REG = tmp | i<<0;  
  48.             break;  
  49.         }  
  50.     }  
  51.     //同时也初始化ch2通道的时钟。   
  52.     #ifdef USE_MMC2   
  53.     /* MMC2 clock src = SCLKMPLL */  
  54.     tmp = CLK_SRC4_REG & ~(0x00000f00);  
  55.     CLK_SRC4_REG = tmp | 0x00000600;  
  56.   
  57.     /* MMC2 clock div */  
  58.     tmp = CLK_DIV4_REG & ~(0x00000f00);  
  59.     CLK_DIV4_REG = tmp | i<<8;  
  60.     #endif   
  61.   
  62. */  
  63. ------------------------------  
  64. //接着设置mmc gpio口的方向   
  65. void setup_hsmmc_cfg_gpio(void)  
  66. {  
  67.     ulong reg;  
  68.     //GPG0 就是一个通道0的接口定义   
  69.     /* MMC channel 0 */  
  70.     /* 7 pins will be assigned - GPG0[0:6] = CLK, CMD, CDn, DAT[0:3] */  
  71.     reg = readl(GPG0CON) & 0xf0000000;  
  72.     //设置为SD接口模式,定义了4bitdata。cmd clk ,cd   
  73.     writel(reg | 0x02222222, GPG0CON);  
  74.     reg = readl(GPG0PUD) & 0xffffc000;  
  75.     //上啦使能,硬件io口需要强制上拉   
  76.     writel(reg | 0x00002aaa, GPG0PUD);  
  77.     writel(0x00003fff, GPG0DRV);  
  78.       
  79.     #ifdef USE_MMC2   
  80.     /* MMC channel 2 */  
  81.     /* 7 pins will be assigned - GPG2[0:6] = CLK, CMD, CDn, DAT[0:3] */  
  82.     reg = readl(GPG2CON) & 0xf0000000;  
  83.     writel(reg | 0x02222222, GPG2CON);  
  84.     reg = readl(GPG2PUD) & 0xffffc000;  
  85.     writel(reg | 0x00002aaa, GPG2PUD);  
  86.     writel(0x00003fff, GPG2DRV);  
  87.   
  88. */  
  89. -----------------------------  
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);

*/
-----------------------------
  1. int smdk_s3c_hsmmc_init(void)  
  2. {  
  3. #ifdef USE_MMC0  //emmc   
  4.     err = s3c_hsmmc_initialize(0);  
  5.   
  6. #endif   
  7. #ifdef USE_MMC2  //sd   
  8.     err = s3c_hsmmc_initialize(2);  
  9. #endif    
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	

 

  1. static int s3c_hsmmc_initialize(int channel)  
  2. {  
  3.     struct mmc *mmc;  
  4.     //定义了4个通道结构体   
  5.     mmc = &mmc_channel[channel];  
  6.     //名称分别是s3c_hsmmc0~3   
  7.     sprintf(mmc->name, "S3C_HSMMC%d", channel);  
  8.     //获取host   
  9.     mmc->priv = &mmc_host[channel];  
  10.     //命令函数   
  11.     mmc->send_cmd = s3c_hsmmc_send_command;  
  12.     //通过core层传递过来的参数,配置host寄存器(时钟,总线宽度等)   
  13.     mmc->set_ios = s3c_hsmmc_set_ios;  
  14. //------------------------------>   
  15.     mmc->init = s3c_hsmmc_init;  
  16. //------------------------------------>   
  17.     //mmc工作电压范围   
  18.     mmc->voltages = MMC_VDD_32_33 | MMC_VDD_33_34;  
  19.     //mmc总线4bit模式,clk 52Hz。 hs模式   
  20.     mmc->host_caps = MMC_MODE_4BIT | MMC_MODE_HS_52MHz | MMC_MODE_HS;  
  21. #if defined(USE_MMC0_8BIT) || defined(USE_MMC2_8BIT)   
  22.     mmc->host_caps |= MMC_MODE_8BIT;  
  23. #endif   
  24.     最小工作平率  
  25.     mmc->f_min = 400000;  
  26.     mmc->f_max = 52000000;  
  27.   
  28.     mmc_host[channel].clock = 0;  
  29.     //系统物理DMA地址   
  30.     switch(channel) {  
  31.     case 0:  
  32.         mmc_host[channel].ioaddr = (void *)ELFIN_HSMMC_0_BASE;  
  33.         break;  
  34.   
  35.     case 2:  
  36.         mmc_host[channel].ioaddr = (void *)ELFIN_HSMMC_2_BASE;  
  37.         break;  
  38.   
  39.     default:  
  40.         printk("mmc err: not supported channel %d\n", channel);  
  41.     }  
  42.       
  43.     return mmc_register(mmc);  
  44. }  
  45.   
  46.  //把mmc这个设备放入链表中   
  47. int mmc_register(struct mmc *mmc)  
  48. {  
  49.     /* Setup the universal parts of the block interface just once */  
  50.     mmc->block_dev.if_type = IF_TYPE_MMC;  
  51. //注意这里,分配当前mmc节点为 cur_dev_num ,第一个位 0,第2个位1。   
  52.     mmc->block_dev.dev = cur_dev_num++;  
  53.     mmc->block_dev.removable = 1;  
  54.       
  55. /*-----------------------------------------------* 
  56.     mmc->block_dev.block_read = mmc_bread; 
  57.     mmc->block_dev.block_write = mmc_bwrite; 
  58. *-----------------------------------------------*/  
  59.     INIT_LIST_HEAD(&mmc->link);  
  60.   
  61.     list_add_tail(&mmc->link, &mmc_devices);  
  62.   
  63.     return 0;  
  64. }  
  65. static int s3c_hsmmc_init(struct mmc *mmc)  
  66. {  
  67.     struct sdhci_host *host = (struct sdhci_host *)mmc->priv;  
  68.     //重设host时钟为0,   
  69.     sdhci_reset(host, SDHCI_RESET_ALL);  
  70.   
  71.     host->version = readw(host->ioaddr + SDHCI_HOST_VERSION);  
  72.     sdhci_init(host);  
  73.   
  74.     sdhci_change_clock(host, 400000);  
  75.   
  76.     return 0;  
  77. }  
  78. 时钟全部初始化完成,返回  
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;
}
时钟全部初始化完成,返回

 

  1. ===============================================  
  2. //根据节点 0 找到mmc的结构   
  3. 这里为什么是只定义0,是因为,当宏定义打开通道2时  
  4.     //,设备只有一个,mmc->block_dev.dev =0++;所以找链表时,就是0 了。     
  5.     //定义了4个通道结构体 mmc = &mmc_channel[2];   
  6.     //如果定义 0 和2, 则会mmc = &mmc_channel[0]  mmc = &mmc_channel[2],   
  7.     //然后一个一个放入链表,dev+1,找通道2时,必须改 find_mmc_device(1);   
  8.     mmc = find_mmc_device(0);  
  9. -------------------------------------------  
===============================================
//根据节点 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);
-------------------------------------------
  1. <PRE class=cpp name="code">struct mmc *find_mmc_device(int dev_num)  
  2. {  
  3.     struct mmc *m;  
  4.     struct list_head *entry;  
  5.   
  6.     list_for_each(entry, &mmc_devices) {  
  7.         m = list_entry(entry, struct mmc, link);  
  8. //根据节点,来获取mmc结构   
  9.         if (m->block_dev.dev == dev_num)  
  10.             return m;  
  11.     }  
  12.   
  13.     printf("MMC Device %d not found\n", dev_num);  
  14.   
  15.     return NULL;  
  16. }  
  17. ====================================  
  18.   
  19. //获取mmc结构后,开始进入mmc_init   
  20.     if (mmc) {  
  21.         err = mmc_init(mmc);  
  22. 至此对sd/mmc初始化部分分析完成。  
  23. ====================================================  
  24. </PRE><BR>  
  25. <PRE></PRE>  
  26. <PRE class=cpp name="code">修改:  
  27. 以前是从NAND flash启动,现在是从emmc启动,修改启动模式:  
  28. /include/configs/smdkv210signle.h  
  29. //#define CFG_FASTBOOT_NANDBSP  //关闭 nand flash启动模式   
  30. #define CFG_FASTBOOT_SDMMCBSP  //打开 sd/mmc启动模式   
  31.   
  32. #define USE_MMC0   //支持 emmc  (占用了通道0)   
  33. #define USE_MMC2   //支持sd  (占用了通道2)   
  34.   
  35. 修改 /drivers/mmc/mmc.c  使它支持 emmc 和sd  
  36.   
  37. int mmc_initialize(bd_t *bis)  
  38. {  
  39.     struct mmc *mmc;  
  40.     int err;  
  41.   
  42.     INIT_LIST_HEAD(&mmc_devices);  
  43.     cur_dev_num = 0;  
  44.   
  45.     if (board_mmc_init(bis) < 0)  
  46.         cpu_mmc_init(bis);  
  47.   
  48. #if defined(DEBUG_S3C_HSMMC)   
  49.     print_mmc_devices(',');  
  50. #endif   
  51.   
  52. #if ( defined(USE_MMC0 ) &&  defined(USE_MMC2 ) )   
  53. //emmc   
  54.     mmc = find_mmc_device(0);  
  55.     if (mmc) {  
  56.         err = mmc_init(mmc);  
  57.         if (err)  
  58.             err = mmc_init(mmc);  
  59.         if (err) {  
  60.             printf("Card init fail!\n");  
  61.             return err;  
  62.         }  
  63.     }  
  64.     printf("emmc  %ldMB\n", (mmc->capacity/(1024*1024/(mmc->read_bl_len))));  
  65. //sd    
  66.     mmc = find_mmc_device(1);  
  67.     if (mmc) {  
  68.         err = mmc_init(mmc);  
  69.         if (err)  
  70.             err = mmc_init(mmc);  
  71.         if (err) {  
  72.             printf("Card init fail!\n");  
  73.             return err;  
  74.         }  
  75.     }  
  76.     printf(" sd  %ldMB\n", (mmc->capacity/(1024*1024/((mmc->read_bl_len)))));  
  77.   
  78.     return 0;  
  79. }  
  80. #else   
  81.     mmc = find_mmc_device(0);  
  82.     if (mmc) {  
  83.         err = mmc_init(mmc);  
  84.         if (err)  
  85.             err = mmc_init(mmc);  
  86.         if (err) {  
  87.             printf("Card init fail!\n");  
  88.             return err;  
  89.         }  
  90.     }  
  91.     printf("%ldMB\n", (mmc->capacity/(1024*1024/(mmc->read_bl_len))));  
  92.     return 0;  
  93. #endif   
  94.   
  95. mmc->read_bl_len :这里要说下此变量,这是emmc 里CSD[80]所定义的,指明了此emmc的块大小,对于SD卡分区格式来说,只支持512 bety 块大小。如果 mmc->read_bl_len =1024  
  96. 的话,对于整个分区体系来说是不支持的,会造成分区不完全。所以后续代码需要修改。  
  97.   
  98. ----------------------------------------------------------------------</PRE><PRE class=cpp name="code"> </PRE>  
  99. <PRE></PRE>  
posted @ 2013-09-05 16:42  莫回头  阅读(1166)  评论(0编辑  收藏  举报