• 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
    ");
            }
            //*/
        #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 }

      








  • 相关阅读:
    exit()和_exit()的比较(与前一篇日志行缓冲区有关)
    标准IO缓冲详解全缓冲、行缓冲、不缓冲
    windows与unix/linux下输入回车换行的区别
    strtok()的用法
    头文件的处理
    feof()出现的问题及解决办法
    测试题
    视觉十四讲:第十二讲_八叉树地图
    树莓派4B安装OPENCV4.0
    编译OpenCV以及openc_contrib提示缺少boostdesc_bgm.i文件出错的解决
  • 原文地址:https://www.cnblogs.com/biaohc/p/6409197.html
Copyright © 2020-2023  润新知