精华内容
下载资源
问答
  • 300系列PLC在下载程序前必须设定一个安全密码,此密码会写在MMC卡里面,而且无法通过PLC拨码初始化,如果忘记密码可以通过使用西门子官方读卡器进行格式化,但是绝对不能插在普通读卡器或者带有读卡器的电脑上,这样...

    西门子300F PLC安全密码

    300系列PLC在下载程序前必须设定一个安全密码,此密码会写在MMC卡里面,而且无法通过PLC拨码初始化,如果忘记密码可以通过使用西门子官方读卡器进行格式化,但是绝对不能插在普通读卡器或者带有读卡器的电脑上,这样操作会导致内存卡误格式化,损坏MMC卡。
    本实验将讲解如何在没有西门子官方读卡器的情况下如何初始化MMC卡,以便MMC卡可以重复使用或在其他设备使用。

    操作前注意事项

    任何拔插MMC卡操作必须关闭对应模块电源后才能操作,否则将会损坏MMC卡和模块!!
    本次实验将会删除mmc卡内所有程序和密码!
    无PLC操作编程经验请勿自行操作或测试,

    注意!!使用此教程执行的所有操作,均需自担风险,使用此教程而造成的任何损失,本人概不负责。

    本次实验使用的硬件设备

    1.PLC主机,带PN口的300系列PLC 本次使用 (151-8FB00-0AB0)
    2.远程IO,一个IM 151-3 PN的模块 推荐使用(151-3BA23-0AB0)
    3.程序卡,被加密的MMC卡(300系列) 在这里插入图片描述

    将新硬件进行组态和IP分配

    将PLC与151-3pn模块进行组态、连接,分配好IP与名称,下载至硬件中,并且无报警和错误信息等故障。在这里插入图片描述

    使用此硬件配合MMC进行操作

    1. 单独将IM 151-3PN模块断电,然后插入带有密码保护的MMC卡插入模块插槽,注意不是插入PLC的插槽,而是已经断电的IM 151-3PN远程IO模块的插槽上
    2.IM 151-3PN模块上电,等待模块运行完毕,直至无红灯报警,待绿色运行灯常量后再次将模块断电,将带密码的MMC卡拔出 ( 此时mmc卡里面内容已经被IM151-3pn模块写入自己的数据并且覆盖掉原内容,所以密码和程序已被删除)
    在这里插入图片描述
    3. 将300PLC断电,然后吧内容已被覆盖的MMC卡插入300PLC,并将PLC上电运行,此时PLC启动后会有报警,并且 STOP指示灯慢闪(提示mmc卡内容不符)
    在这里插入图片描述

    4. **重要!!此步骤为重置MMC卡 (
    )
    1.将此PLC拨码一直拨到最底部(MRES)直至STOP灯常亮(此时stop灯将会快闪后慢闪在常亮)
    2.STOP指示灯常亮后迅速松开(回弹至stop档位)
    3.在1秒内再次迅速按下到复位档(MRES)
    4.在1秒内再次迅速松开(回弹至stop档位)(此时plc会stop指示灯会快闪后常亮)
    5.stop指示灯常亮后将拨码拨至运行处(RUN)
    这时候PLC已经正常运行并且无报警就表示MMC卡已经重置成功,重新下载程序即可使用。

    见动图五

    本帖仅供学习与交流,在工作中遇到的问题与事情,欢迎一起交流学习。

    	                                                                                                        WLang21_S-L01
    
    展开全文
  • SD SDIO MMC 初始化经典解析
  • 新唐NUC977开发板uboot代码解析3-SD卡初始化mmc相关命令
  • sd/mmc初始化

    千次阅读 2012-06-25 09:33:30
    [cpp] view plaincopy...1.首先分析 sd/mmc 初始化: // board.c puts ("SD/MMC: "); mmc_exist = mmc_initialize(gd->bd); /////////////////////////////////////////////////////////////////////////////
    [cpp] view plaincopyprint?

    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);

    */
    -----------------------------

    [cpp] view plaincopyprint?

    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


    [cpp] view plaincopyprint?

    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;
    }
    时钟全部初始化完成,返回


    [cpp] view plaincopyprint?

    ===============================================
    //根据节点 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);
    -------------------------------------------

    [cpp] view plaincopyprint?

    <pre class="cpp" name="code">struct mmc *find_mmc_device(int dev_num)
    {
    struct mmc *m;
    struct list_head *entry;

    list_for_each(entry, &mmc_devices) {
    m = list_entry(entry, struct mmc, link);
    //根据节点,来获取mmc结构
    if (m->block_dev.dev == dev_num)
    return m;
    }

    printf("MMC Device %d not found\n", dev_num);

    return NULL;
    }
    ====================================

    //获取mmc结构后,开始进入mmc_init
    if (mmc) {
    err = mmc_init(mmc);
    至此对sd/mmc初始化部分分析完成。
    ====================================================


    [cpp] view plaincopyprint?

    修改:
    以前是从NAND flash启动,现在是从emmc启动,修改启动模式:
    /include/configs/smdkv210signle.h
    //#define CFG_FASTBOOT_NANDBSP //关闭 nand flash启动模式
    #define CFG_FASTBOOT_SDMMCBSP //打开 sd/mmc启动模式

    #define USE_MMC0 //支持 emmc (占用了通道0)
    #define USE_MMC2 //支持sd (占用了通道2)

    修改 /drivers/mmc/mmc.c 使它支持 emmc 和sd

    int mmc_initialize(bd_t *bis)
    {
    struct mmc *mmc;
    int err;

    INIT_LIST_HEAD(&mmc_devices);
    cur_dev_num = 0;

    if (board_mmc_init(bis) < 0)
    cpu_mmc_init(bis);

    #if defined(DEBUG_S3C_HSMMC)
    print_mmc_devices(',');
    #endif

    #if ( defined(USE_MMC0 ) && defined(USE_MMC2 ) )
    //emmc
    mmc = find_mmc_device(0);
    if (mmc) {
    err = mmc_init(mmc);
    if (err)
    err = mmc_init(mmc);
    if (err) {
    printf("Card init fail!\n");
    return err;
    }
    }
    printf("emmc %ldMB\n", (mmc->capacity/(1024*1024/(mmc->read_bl_len))));
    //sd
    mmc = find_mmc_device(1);
    if (mmc) {
    err = mmc_init(mmc);
    if (err)
    err = mmc_init(mmc);
    if (err) {
    printf("Card init fail!\n");
    return err;
    }
    }
    printf(" sd %ldMB\n", (mmc->capacity/(1024*1024/((mmc->read_bl_len)))));

    return 0;
    }
    #else
    mmc = find_mmc_device(0);
    if (mmc) {
    err = mmc_init(mmc);
    if (err)
    err = mmc_init(mmc);
    if (err) {
    printf("Card init fail!\n");
    return err;
    }
    }
    printf("%ldMB\n", (mmc->capacity/(1024*1024/(mmc->read_bl_len))));
    return 0;
    #endif

    mmc->read_bl_len :这里要说下此变量,这是emmc 里CSD[80]所定义的,指明了此emmc的块大小,对于SD卡分区格式来说,只支持512 bety 块大小。如果 mmc->read_bl_len =1024
    的话,对于整个分区体系来说是不支持的,会造成分区不完全。所以后续代码需要修改。

    ----------------------------------------------------------------------
    展开全文
  • 为了学习SD/SDIO协议,看了一下linux中初始化SD卡的流程,结合代码更容易SD初始化是怎么做的。 下面图截自:"SD Specifications Part 1 Physical Layer Simplified Specification Version 4.10" SD卡在sd模式下的...
     

    为了学习SD/SDIO协议,看了一下linux中初始化SD卡的流程,结合代码更容易SD初始化是怎么做的。

    下面图截自:"SD Specifications Part 1 Physical Layer Simplified Specification Version 4.10"

    SD卡在sd模式下的初始化流程图,sd协议还有spi模式暂不研究。

    这个流程图对应于linux 代码就在

    /driver/mmc/core/sd.c

    static int mmc_sd_init_card(struct mmc_host *host, u32 ocr, struct mmc_card *oldcard)

    传入参数

    truct mmc_host *host mmc/sd/sdio主机控器的结构,成员用到再说明

    u32 ocr 这个比较重要,与ACMD41和sd卡中ocr寄存器相关。调用mmc_sd_init_card之前

    linux已经做过一些工作,就是发送ACMD41获取SD卡工作电压,与Host支持电压匹配并设置host的电压,然后调用mmc_sd_init_card,并把电压信息通过ocr传递下来。流程图开始时这些工作已经做好。

    struct mmc_card *oldcard  新插入的卡初始化时该值为NULL。

    linux版本3.7 mmc_sd_init_card函数:

    复制代码
      1 /*
      2  * Handle the detection and initialisation of a card.
      3  *
      4  * In the case of a resume, "oldcard" will contain the card
      5  * we're trying to reinitialise.
      6  */
      7 static int mmc_sd_init_card(struct mmc_host *host, u32 ocr,
      8     struct mmc_card *oldcard)
      9 {
     10     struct mmc_card *card;
     11     int err;
     12     u32 cid[4];
     13     u32 rocr = 0;
     14 
     15     BUG_ON(!host);
     16     WARN_ON(!host->claimed);
     17 
     18     err = mmc_sd_get_cid(host, ocr, cid, &rocr);
     19     if (err)
     20         return err;
     21 
     22     if (oldcard) {
     23         if (memcmp(cid, oldcard->raw_cid, sizeof(cid)) != 0)
     24             return -ENOENT;
     25 
     26         card = oldcard;
     27     } else {
     28         /*
     29          * Allocate card structure.
     30          */
     31         card = mmc_alloc_card(host, &sd_type);
     32         if (IS_ERR(card))
     33             return PTR_ERR(card);
     34 
     35         card->type = MMC_TYPE_SD;
     36         memcpy(card->raw_cid, cid, sizeof(card->raw_cid));
     37     }
     38 
     39     /*
     40      * For native busses:  get card RCA and quit open drain mode.
     41      */
     42     if (!mmc_host_is_spi(host)) {
     43         err = mmc_send_relative_addr(host, &card->rca);
     44         if (err)
     45             return err;
     46     }
     47 
     48     if (!oldcard) {
     49         err = mmc_sd_get_csd(host, card);
     50         if (err)
     51             return err;
     52 
     53         mmc_decode_cid(card);
     54     }
     55 
     56     /*
     57      * Select card, as all following commands rely on that.
     58      */
     59     if (!mmc_host_is_spi(host)) {
     60         err = mmc_select_card(card);
     61         if (err)
     62             return err;
     63     }
     64 
     65     err = mmc_sd_setup_card(host, card, oldcard != NULL);
     66     if (err)
     67         goto free_card;
     68 
     69     /* Initialization sequence for UHS-I cards */
     70     if (rocr & SD_ROCR_S18A) {
     71         err = mmc_sd_init_uhs_card(card);
     72         if (err)
     73             goto free_card;
     74 
     75         /* Card is an ultra-high-speed card */
     76         mmc_card_set_uhs(card);
     77 
     78         /*
     79          * Since initialization is now complete, enable preset
     80          * value registers for UHS-I cards.
     81          */
     82         if (host->ops->enable_preset_value) {
     83             mmc_host_clk_hold(card->host);
     84             host->ops->enable_preset_value(host, true);
     85             mmc_host_clk_release(card->host);
     86         }
     87     } else {
     88         /*
     89          * Attempt to change to high-speed (if supported)
     90          */
     91         err = mmc_sd_switch_hs(card);
     92         if (err > 0)
     93             mmc_sd_go_highspeed(card);
     94         else if (err)
     95             goto free_card;
     96 
     97         /*
     98          * Set bus speed.
     99          */
    100         mmc_set_clock(host, mmc_sd_get_max_clock(card));
    101 
    102         /*
    103          * Switch to wider bus (if supported).
    104          */
    105         if ((host->caps & MMC_CAP_4_BIT_DATA) &&
    106             (card->scr.bus_widths & SD_SCR_BUS_WIDTH_4)) {
    107             err = mmc_app_set_bus_width(card, MMC_BUS_WIDTH_4);
    108             if (err)
    109                 goto free_card;
    110 
    111             mmc_set_bus_width(host, MMC_BUS_WIDTH_4);
    112         }
    113     }
    114 
    115     host->card = card;
    116     return 0;
    117 
    118 free_card:
    119     if (!oldcard)
    120         mmc_remove_card(card);
    121 
    122     return err;
    123 }
    复制代码

    18行,err = mmc_sd_get_cid(host, ocr, cid, &rocr);字面意思就是获取CID,对照着流程图给该函数注释:

    复制代码
     1 /*
     2  * Fetch CID from card.
     3  */
     4 int mmc_sd_get_cid(struct mmc_host *host, u32 ocr, u32 *cid, u32 *rocr)
     5 {
     6     int err;
     7     u32 max_current;
     8 
     9     /*
    10      * Since we're changing the OCR value, we seem to
    11      * need to tell some cards to go back to the idle
    12      * state.  We wait 1ms to give cards time to
    13      * respond.
    14      */
    15     mmc_go_idle(host);//发送CMD0
    16 
    17     /*
    18      * If SD_SEND_IF_COND indicates an SD 2.0
    19      * compliant card and we should set bit 30
    20      * of the ocr to indicate that we can handle
    21      * block-addressed SDHC cards.
    22      */
    23     err = mmc_send_if_cond(host, ocr);//发送CMD8,
    24     if (!err)
    25         ocr |= SD_OCR_CCS;//如果返回失败,说明卡不是SD2.0或之后的版本,如果是2.0的SD卡,把ocr的30位置1,即协议里ACMD41命令中的HCS.
    26 表示支持SDHC或SDXC,ACMD41命令见下面图示
    27     /*
    28      * If the host supports one of UHS-I modes, request the card
    29      * to switch to 1.8V signaling level.
    30      */
    31     if (host->caps & (MMC_CAP_UHS_SDR12 | MMC_CAP_UHS_SDR25 |
    32         MMC_CAP_UHS_SDR50 | MMC_CAP_UHS_SDR104 | MMC_CAP_UHS_DDR50))
    33         ocr |= SD_OCR_S18R; //判断主机控制器是否支持UHS-I host->caps通常在主机控制器驱动的probe函数里面初始化,值和具体主机控制器
                        有关.如果支持那么就把ocr的24位置1,即ACMD41命令的S18R.表示要求SD卡准备切换到1.8V电压模式
    34 
    35     /*
    36      * If the host can supply more than 150mA at current voltage,
    37      * XPC should be set to 1.
    38      */
    39     max_current = sd_get_host_max_current(host);
    40     if (max_current > 150)
    41         ocr |= SD_OCR_XPC;//SDXC中Power Control相关的项,ocr第28位,ACMD41中的XPC
    42
    43 try_again:
    44     err = mmc_send_app_op_cond(host, ocr, rocr);//发送ACMD41,这个函数你可以进去看一下,会发现循环检验ACMD41的,应答值的31位,与
    协议流程图中符合.rocr就是卡对ACMD41的应答值.另外ACMD41属于app cmd需要先发送CMD55,这个linux都封装在了函数里,并且流程图上也简化掉了.
                                    
    45     if (err)
    46         return err;
    47 
    48     /*
    49      * In case CCS and S18A in the response is set, start Signal Voltage
    50      * Switch procedure. SPI mode doesn't support CMD11.
    51      */
    52     if (!mmc_host_is_spi(host) && rocr &&
    53        ((*rocr & 0x41000000) == 0x41000000)) {//这个if语句,先判断是不是spi模式,是spi模式就不继续,我只分析SD模式所以继续
    判断rocr即ACMD41的应答值的CSS(30位)和S18A(24位)这两位具体意义见代码下面的图表.只有当sd卡是SDHC或SDXC,并且SD卡准备好切换电压模式,才切换
    SDSC不进行切换.
    54         err = mmc_set_signal_voltage(host, MMC_SIGNAL_VOLTAGE_180, true);//发送CMD11切换,主机端也做相应的处理.
    55         if (err) {
    56             ocr &= ~SD_OCR_S18R;
    57             goto try_again;
    58         }
    59     }
    60 
    61     if (mmc_host_is_spi(host))
    62         err = mmc_send_cid(host, cid);
    63     else
    64         err = mmc_all_send_cid(host, cid);//发送CMD2.获取cid,即Card IDentification register,存放了一些卡的信息,
    到这里发现已经到了流程图的底部,只剩CMD3了
    65 
    66     return err;
    67 }
    复制代码

    ACMD41命令:


     

    图中红线标出的就是代码中rocr的值.关于该命令更多的内容见SD的spec.

     

    回到mmc_sd_init_card函数,

    22~37行与协议无关,主要是初始化一个struct mmc_card *card结构体.这个结构体就相当于这张卡的身份证,从卡的CID,CSD..寄存器拿到的值都要填到该结构中备用.

    43行 err = mmc_send_relative_addr(host, &card->rca),发送CMD3获取RCA,得到卡的地址.流程图到这里就结束了. mmc_sd_init_card却没有结束.

    接下来还要获取SD卡的CSD寄存器的值,来填充struct mmc_card *card结构体.

    49行 err = mmc_sd_get_csd(host, card);发送CMD9获取CSD并解析,填充到card.CSD寄存器保存了大量卡的信息.

    53行 mmc_decode_cid(card); 解析前面获得的CID并填充到card,这一步为什么不在前面获得cid的时候做? 是因为sd卡协议有不同版本而版本信息放在CSD中,所以需要先得到CSD,获得版本号,在根据版本号解析CID中的数据. 详细内容见spec中寄存器部分.

    60行 err = mmc_select_card(card);发送CMD7使用上面得到的地址选择卡

    65行 err = mmc_sd_setup_card(host, card, oldcard != NULL);发送ACMD51获取SCR寄存器值,发送ACMD13获取SD卡状态信息,解析并填充card结构,SCR寄存器是对CSD的补充.
    最后69~113行 if else语句,判断是否是UHS-I,分别进行处理.先看一下esle中的代码

    先调用 err = mmc_sd_switch_hs(card);,支持高速就发命令把卡设置到高速

     

    复制代码
     1 int mmc_sd_switch_hs(struct mmc_card *card)
     2 {
     3     int err;
     4     u8 *status;
     5 
     6     if (card->scr.sda_vsn < SCR_SPEC_VER_1)//判断卡的版本,SD1.1和之后的版本支持高速
     7         return 0;
     8 
     9     if (!(card->csd.cmdclass & CCC_SWITCH))//判断是否支持class10命令
    10         return 0;
    11 
    12     if (!(card->host->caps & MMC_CAP_SD_HIGHSPEED))//判断主机控制器是否支持高速卡
    13         return 0;
    14 
    15     if (card->sw_caps.hs_max_dtr == 0)/*这个值什么情况下会为0? 该值赋值是在mmc_read_switch函数中,发送CMD6命令时赋值的,如果不支持HIGHSPEED就没有赋值.
    16 通常sd卡驱动中使用CMD6命令,都会发送两次,第一次查询卡是否支持接下来要做的切换(在mmc_read_switch中).
    17 第二次执行切换操作.CMD6命令详细内容见spec*/
    18         return 0;
    19 
    20     err = -EIO;
    21 
    22     status = kmalloc(64, GFP_KERNEL);//分配64bytes的空间.用于接收CMD6的应答数据.
    23     if (!status) {
    24         pr_err("%s: could not allocate a buffer for "
    25             "switch capabilities.\n", mmc_hostname(card->host));
    26         return -ENOMEM;
    27     }
    28 
    29     err = mmc_sd_switch(card, 1, 0, 1, status);//发送CMD6切换卡到高速
    30     if (err)
    31         goto out;
    32 
    33     if ((status[16] & 0xF) != 1) {//切换结果在第17字节,也是spec中规定的
    34         pr_warning("%s: Problem switching card "
    35             "into high-speed mode!\n",
    36             mmc_hostname(card->host));
    37         err = 0;
    38     } else {
    39         err = 1;
    40     }
    41 
    42 out:
    43     kfree(status);
    44 
    45     return err;
    46 }
    复制代码

    93行,设置主机这边,最终会调用host驱动,与你host硬件有关.

    100行,mmc_set_clock(host, mmc_sd_get_max_clock(card));//设置时钟频率,mmc_sd_get_max_clock(card)是用的card->sw_caps.hs_max_dtr或card->csd.max_dtr.如果支持高速linux会设置为card->sw_caps.hs_max_dtr,这个值在之前被赋为

    50000000.

    105~111 同样需要host和card同时支持4bit宽度,才能设置,并且要同时设置host和card

    err = mmc_app_set_bus_width(card, MMC_BUS_WIDTH_4);设置卡的总线宽度,使用的命令是ACMD6

     

    至此,mmc_sd_init_card函数就结束了. linux中的初始化处理过程基本上与spec中的流程图相符. 之后还有设置时钟,设置数据线宽度等操作.

    还有一个关于UHS-I的分支没有分析,这个放到下篇分析.并且其中又涉及到CMD6,顺便简单分析学习一下CMD6的使用.

    转载于:https://www.cnblogs.com/yanghong-hnu/p/4671357.html

    展开全文
  • 1. mmc_init /** * drivers/mmc/core/core.c */ static int __init mmc_init(void) { int ret; ret = mmc_register_bus(); if (ret) return ret; ret = mmc_register_host_class(); if (ret) goto ...

    目录

    1. mmc_init

    2. mmc_register_bus

    3. mmc_register_host_class

    4. mmc blk驱动注册

    5. mmc_register_driver


    1. mmc_init

    /**
     * drivers/mmc/core/core.c
     */
    static int __init mmc_init(void)
    {
    	int ret;
    
    	ret = mmc_register_bus();
    	if (ret)
    		return ret;
    
    	ret = mmc_register_host_class();
    	if (ret)
    		goto unregister_bus;
    
    	ret = sdio_register_bus();  //只分析mmc bus,sdio bus暂且不做分析
    	if (ret)
    		goto unregister_host_class;
    
    	return 0;
    
    unregister_host_class:
    	mmc_unregister_host_class();
    unregister_bus:
    	mmc_unregister_bus();
    	return ret;
    }
    
    subsys_initcall(mmc_init);

    2. mmc_register_bus

    /**
     * drivers/mmc/core/bus.c
     */
    #define to_mmc_driver(d)	container_of(d, struct mmc_driver, drv)
    
    
    /**
     * drivers/mmc/core/card.h
     */ 
    #define mmc_dev_to_card(d)	container_of(d, struct mmc_card, dev)
    
    
    /**
     * drivers/mmc/core/bus.c
     */
    /*
     * This currently matches any MMC driver to any MMC card - drivers
     * themselves make the decision whether to drive this card in their
     * probe method.
     */
    static int mmc_bus_match(struct device *dev, struct device_driver *drv)
    {
    	return 1;
    }
    
    
    /**
     * drivers/mmc/core/bus.c
     */
    static int mmc_bus_probe(struct device *dev)
    {
    	struct mmc_driver *drv = to_mmc_driver(dev->driver);
    	struct mmc_card *card = mmc_dev_to_card(dev);
    
    	return drv->probe(card);
    }
    
    
    /**
     * drivers/mmc/core/bus.c
     */
    static struct bus_type mmc_bus_type = {
    	.name		= "mmc",
    	.dev_groups	= mmc_dev_groups,
    	.match		= mmc_bus_match,
    	.uevent		= mmc_bus_uevent,
    	.probe		= mmc_bus_probe,
    	.remove		= mmc_bus_remove,
    	.shutdown	= mmc_bus_shutdown,
    	.pm		= &mmc_bus_pm_ops,
    };
    
    int mmc_register_bus(void)
    {
    	return bus_register(&mmc_bus_type);
    }

    3. mmc_register_host_class

    /**
     * drivers/mmc/core/host.c
     */
    static struct class mmc_host_class = {
    	.name		= "mmc_host",
    	.dev_release	= mmc_host_classdev_release,
    };
    
    int mmc_register_host_class(void)
    {
    	return class_register(&mmc_host_class);
    }

    4. mmc blk驱动注册

    /**
     * drivers/mmc/core/block.c
     */
    static struct mmc_driver mmc_driver = {
            .drv            = {
                    .name   = "mmcblk",
                    .pm     = &mmc_blk_pm_ops,
            },
            .probe          = mmc_blk_probe,
            .remove         = mmc_blk_remove,
            .shutdown       = mmc_blk_shutdown,
    };
    
    static int __init mmc_blk_init(void)
    {
            int res; 
    
            if (perdev_minors != CONFIG_MMC_BLOCK_MINORS)
                    pr_info("mmcblk: using %d minors per device\n", perdev_minors);
    
            max_devices = min(MAX_DEVICES, (1 << MINORBITS) / perdev_minors);
    
            res = register_blkdev(MMC_BLOCK_MAJOR, "mmc");
            if (res)
                    goto out; 
    
            /**
             * 见5. mmc_register_driver
             */
            res = mmc_register_driver(&mmc_driver);
            if (res)
                    goto out2;
    
            return 0;
     out2:
            unregister_blkdev(MMC_BLOCK_MAJOR, "mmc");
     out: 
            return res; 
    }
    
    
    module_init(mmc_blk_init);

    5. mmc_register_driver

    /**
     * drivers/mmc/core/bus.c
     */
    static struct bus_type mmc_bus_type = {
            .name           = "mmc",
            .dev_groups     = mmc_dev_groups,
            .match          = mmc_bus_match,
            .uevent         = mmc_bus_uevent,
            .probe          = mmc_bus_probe,
            .remove         = mmc_bus_remove,
            .shutdown       = mmc_bus_shutdown,
            .pm             = &mmc_bus_pm_ops,
    };
    
    
    /**
     * drivers/mmc/core/bus.c
     */
    /**
     *      mmc_register_driver - register a media driver
     *      @drv: MMC media driver
     */
    int mmc_register_driver(struct mmc_driver *drv)
    {
            drv->drv.bus = &mmc_bus_type;
            return driver_register(&drv->drv);
    }
    

     

    展开全文
  • mmc_sd_init_card剩下的关于UHS-I的分支...uhs-I的初始化流程图如图: 红线标出的部分是已经做了的事,与上一篇那个流程图是一致的,之后就是if分支中做的事。 if分支中的函数mmc_sd_init_uhs_card:...
  • MMC无法初始化管理单元

    千次阅读 2010-08-27 16:04:00
    在sql2000和sql2005之间折腾,把sql2005完整开发版卸载了,安装了精简版的sql2005后,再打开sql2000的企业管理器的时候,系统就提示“管理单元初始化失败,名称未知,CLSID:{00100100-1816-11D0-8EF5-00AA0062...
  • Linux mmc驱动框架Host驱动设备树Host驱动platform_driver数据结构初始化第一阶段 Host驱动设备树   host驱动设备树用于匹配host驱动,host驱动匹配上设备树,初始化流程才能开始。本文举例全志H3设备树以及mmc...
  • SD/MMC初始化及读写流程

    千次阅读 2017-11-10 11:15:46
    二、MMC/SD卡的模型和工作原理 PIN脚、SD卡总线、SD卡结构、SD卡寄存器、上电过程 SD卡寄存器:  OCR:操作电压寄存器: 只读,32位 第31位: 表示卡上电的状态位   CID: 卡身份识别寄存器 只读 128位 生产...
  • Linux mmc驱动框架卡检测函数`mmc_rescan``mmc_rescan->mmc_rescan_try_freq`SDIO卡`mmc_rescan->mmc_rescan_try_freq->mmc_attach_sdio`SD卡`mmc_rescan->mmc_rescan_try_freq->mmc_attach_sd`MMC卡...
  • SD/MMC 初始化及热插拔检测机制

    千次阅读 2015-07-22 16:03:01
    SD卡的技术是基于MultiMedia卡(MMC)格式上发展而来,SD卡与MMC卡保持着向上兼容。SD卡的内部结构主要分两部分:SD控制器和NAND存储器。  SD卡类型总共分成三种:MMC卡,结构类似SD卡,采用MMC协议;SD1.0,SD1.0...
  • 下面是对QualComm 8x50 上MMC host controller 驱动的初始化流程分析. 分析基于kernel 2.6.29 版本 (主要的代码为 driver/mmc/msm_sdcc.c 和 msm_sdcc.h 以及 arch 下的代码) 1. MMC 中涉及的总线类型 MMC 目录...
  • linux SD卡初始化---mmc_sd_init_card函数

    千次阅读 2015-03-27 17:03:55
    为了学习SD/SDIO协议,看了一下linux中初始化SD卡的流程,结合代码更容易SD初始化是怎么做的。 下面图截自:"SD Specifications Part 1 Physical Layer Simplified Specification Version 4.10" SD卡在sd模式下的...
  • bbb u-boot mmc总线初始化分析

    千次阅读 2015-01-26 00:00:02
    前两布应该还没有初始化串口,所以看不到打印 3. arch/arm/lib/board.c //从 这个函数开始才有打印,而且函数的开头部分也没有打印 void board_init_r(gd_t *id, ulong dest_addr) {  puts...
  • http://blog.csdn.net/yunfly163/article/details/7495162 [cpp] view ...1.首先分析 sd/mmc 初始化:   // board.c  puts ("SD/MMC: ");  mmc_exist = mmc_initialize(gd->bd)
  • http://blog.csdn.net/yunfly163/article/details/7495162   [cpp] ...1.首先分析 sd/mmc 初始化: // board.c puts ("SD/MMC: "); mmc_exist = mmc_initialize(gd->bd); /////////
  • uhs-I的初始化流程图如图: 红线标出的部分是已经做了的事,与上一篇那个流程图是一致的,之后就是if分支中做的事。 if分支中的函数mmc_sd_init_uhs_card: /* * UHS-I specific initialization procedure ...

空空如也

空空如也

1 2 3 4 5 ... 18
收藏数 347
精华内容 138
关键字:

初始化mmc