子系统概述

    Linux kernel把mmc,sd以及sdio三者的驱动代码整合在一起,称mmc子系统。源码位于drivers/mmc下。

    其下有三个子目录,分别是:card,core,host。

  • card:构建一个块设备作为上层与mmc子系统沟通的桥梁;
  • core:抽象了mmc,sd,sdio三者的操作。核心层封装了 MMC/SD 卡的命令,例如存储卡的识别,设置,读写。例如不管什么卡都应该有一些识别,设置,和读写的命令,这些流程都是必须要有的,只是具体对于不同的卡会有一些各自特有的操作。 core.c 文件是由 sd.c 、 mmc.c 两个文件支撑, core.c 把 MMC 卡、 SD 卡的共性抽象出来,它们的差别由 sd.c 和 sd_ops.c 、 mmc.c 和 mmc_ops.c 来完成。
  • host:则是各类平台上的host驱动代码,包括如TI Omap的omap_hsmmc,三星的s3cmci等。

源码位置

命令号:include/linux/mmc/mmc.h

相关节点


节点



含义



/dev/mmcblk0boot0



boot0分区。主设备号:179;次设备号:8     



/dev/mmcblkb0oot1



boot0分区。主设备号:179;次设备号:9   



/dev/mmc0        



主节点。   主设备号:179;次设备号:0



/dev/mmc01       



第1个分区。主设备号:179;次设备号:1



...              






/dev/mmc07       



第7个分区。主设备号:179;次设备号:7



/dev/mmc08       



第8个分区。主设备号:259;次设备号:0



...              






/dev/mmc09       



第9个分区。主设备号:259;次设备号:1



/dev/mmcblk0p10  



第9个分区。主设备号:259;次设备号:2


...

card路径代码分析

mmc/card/block.c

mmc_blk_probe

    详细流程见:控制器代码分析=>mmc_blk_probe

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,

};

mmc_blk_init

        //设置次设备数、主设备数

        perdev_minors = CONFIG_MMC_BLOCK_MINORS

        max_devices = min(MAX_DEVICES, (1 << MINORBITS) / perdev_minors);

        //MMC_BLOCK_MAJOR是179

        register_blkdev(MMC_BLOCK_MAJOR, "mmc");   //block/genhd.c

        mmc_register_driver(&mmc_driver)                           //mmc/core/bus.c

                drv->drv.bus = &mmc_bus_type

                driver_register(&drv->drv)

module_init(mmc_blk_init);

读写流程

mmc_queue_thread是在mmc_init_queue中起的线程,主要作用是完成上层发送的请求进行处理。

mmc_queue_thread                                              //mmc/card/queue.c

        struct  mmc_queue  *mq  =  d;

        struct  request_queue  *q  =  mq->queue;

        req  =  blk_fetch_request(q);                                                //block/blk-core.c

                mmc_blk_issue_rq(mq,  req);                                        //mmc/card/block.c

                        //切换分区:选择要使用哪个分区。(boot还是user  data等)

                        mmc_blk_part_switch(card,  md);                //mmc/card/block.c

                        //根据req->cmd_flags确定操作:REQ_OP_READ、REQ_OP_WRITE、REQ_OP_FLUSH等

                        //读写以外的操作,第2个参数都是NULL

                        mmc_blk_issue_rw_rq(mq,  req);                        //mmc/card/block.c

                                //尝试把当前request和队列中的其他request合并,以增强性能

                                mmc_blk_prep_packed_list(mq,  rqc);        //mmc/card/block.c

                                //正常走此分支:设置读写命令号(多/单 块)等

                                mmc_blk_rw_rq_prep(mq->mqrq_cur,  card,  0,  mq);                                //mmc/card/block.c  

                                mmc_start_req(card->host,  areq,  (int  *)  &status);                                     //mmc/core/core.c

                                        //传进来第2个参数名为mrq

                                        mmc_wait_for_data_req_done(host,  host->areq->mrq,  areq);         //mmc/core/core.c

                                                //等待。退出条件:上一个请求结束或者本请求是新请求

                                                wait_event_interruptible(context_info->wait,  (context_info->is_done_rcv  ||  

                                                                                                                     context_info->is_new_req));

                                                __mmc_start_request(host,  mrq);                        //mmc/core/core.c

                                                        mmc_retune(host);           //mmc/core/host.c

                                                                if (!​host->need_retune​ || host->doing_retune || !host->card)

                                                                        return 0;

                                                        host->ops->request(host,  mrq);

控制器代码分析

控制器入口

mmc/host/myhost_mmc.c

myhost_mmc_probe(struct platform_device *pdev)         //myhost_mmc.c

        struct sdhci_host *host;

        struct mmc_host *mmc = NULL;

        mmc = mmc_alloc_host(sizeof(struct myhost_mmc_host), &pdev->dev);       //core/host.c

                //传进来第2个参数名为dev

                struct mmc_host *host;

                host = kzalloc(sizeof(struct mmc_host) + extra, GFP_KERNEL);

                host->parent = dev;

                init_waitqueue_head(&host->wq);

                INIT_DELAYED_WORK(&host->detect, mmc_rescan);     //mmc_rescan在 core/core.c定义

        platform_set_drvdata(pdev, mmc);

                pdev->dev.driver_data = mmc

        host = mmc_priv(mmc);         //host = mmc->private

        host->mmc = mmc;

        mmc->ops = &myhost_mmc_ops;

        host->dma_des = dma_alloc_coherent(&pdev->dev, MAX_DMA_DES * sizeof(desc_tab),

            &host->dma_des_phy, GFP_KERNEL);

        mmc_of_parse(host->mmc)         //core/host.c

                解析bus_width,max-frequency,写保护、速率、电压等

        myhost_mmc_host_init(host);

        irq = platform_get_irq(pdev, 0);

        host->irq = irq;

        request_threaded_irq()

        tasklet_init(&host->finish_tasklet,    myhostmmc_tasklet_finish, (unsigned long)host);

        setup_timer(&host->timer, myhostmmc_timeout_timer, (unsigned long)host);

        mmc_add_host(mmc);                //core/host.c

                //传进来的参数名为host

                device_add(&host->class_dev);

                led_trigger_register_simple(dev_name(&host->class_dev), &host->led);    //drivers/leds/led-trigger.c

                mmc_start_host(host);         //core/core.c

                        mmc_claim_host(host); //mmc/core.h

                                __mmc_claim_host(host, NULL);         //core/core.c

                                        host->claimed = 1;

                                host->claimer = current;

                                host->claim_cnt += 1;

                        mmc_power_up(host, host->ocr_avail) //core/core.c

                                mmc_set_initial_state(host);                        //core/core.c

                                        //传进来参数名为host

                                        mmc_retune_disable(host);       //mmc/core/host.c

                                                host->​need_retune​ = 0;

                                        给host->ios的bus_mode,bus_width,timing等赋值

                                        mmc_set_ios(host);                              //core/core.c

                                                host->ops->set_ios(host, ios);

                               //依次尝试切换为:3.3v,1.8v,1.2v

                                __mmc_set_signal_voltage(host, MMC_SIGNAL_VOLTAGE_330)          //core/core.c

                                        //设置host的电压

                                        host->ops->start_signal_voltage_switch(host, &host->ios)

                                        dev_dbg(mmc_dev(host), "Initial signal voltage of ...v\n");

                                host->ios.clock = host->f_init;

                                host->ios.power_mode = MMC_POWER_ON;

                                mmc_set_ios(host)                                            //core/core.c

                                        host->ops->set_ios(host, ios);

                        mmc_gpiod_request_cd_irq(host);                         //core/slot-gpio.c

                        _mmc_detect_change(host, 0, false);                     //core/core.c                                

                                host->detect_change = 1;

                                mmc_schedule_delayed_work(&host->detect, delay);           //core/core.c

                                queue_delayed_work(system_freezable_wq, work, delay); //include/linux/workqueue.h

                                        mmc_rescan        //core/core.c           会被调用到   

mmc_rescan

//core/core.c: static const unsigned freqs[] = { 400000, 300000, 200000, 100000 };

mmc_rescan(struct work_struct *work)        //core/core.c

        struct mmc_host *host = container_of(work, struct mmc_host, detect.work);

        //​非核心函数暂时忽略

        host->rescan_entered = 1;

        host->detect_change = 0;

        for (i = 0; i < ARRAY_SIZE(freqs); i++) {

                if (!mmc_rescan_try_freq(host, max(freqs[i], host->f_min)))

                        break;

                if (freqs[i] <= host->f_min)

                        break;

        }

mmc_rescan_try_freq

mmc_rescan_try_freq(host, max(freqs[i], host->f_min)                //core/core.c

        //传进来第1个参数为:struct mmc_host *host

        mmc_power_up(host, host->ocr_avail);        //core/core.c

                //host->ocr_avail在控制器驱动中指定的。此函数流程在上边有。

                ...

                host->ops->set_ios(host, ios);

        mmc_hw_reset_for_init(host);        //core/core.c

                host->ops->hw_reset(host);

        //命令号:0;参数:0

        mmc_go_idle(host);

        //命令号:8。为了兼容SD2.0。 MMC_CAP2_NO_SD对应于设备树的no-sd。

        if (!(host->caps2 & MMC_CAP2_NO_SD))

                mmc_send_if_cond(host, host->ocr_avail);


        //依次探测SDIO,SD,eMMC(顺序很重要)

        ​mmc_attach_mmc​(host)                                //core/mmc.c

                //传进来第1个参数为:struct mmc_host *host

                如果host不是spi模式         //!((host)->caps & MMC_CAP_SPI)

                        //一般走此分支。只有mmc/host/mmc_spi.c会指定为MMC_CAP_SPI

                        mmc_set_bus_mode(host, MMC_BUSMODE_OPENDRAIN);                //core/core.c

                                mmc_set_ios(host);        //mmc/core/core.c

                //命令号:2;参数:0

                mmc_send_op_cond(host, 0, &ocr);        //core/mmc_ops.c

                        //传进来第二个参数名为ocr,第三个参数名为rocr

                        cmd.flags = MMC_RSP_SPI_R1 | MMC_RSP_R3 | MMC_CMD_BCR;

                        //发送命令并等待命令结束

                        mmc_wait_for_cmd(host, &cmd, 0)   //mmc/core/core.c

                                 //第2个参数名:cmd

                                 struct mmc_request mrq = {NULL};

                                 mrq.cmd = cmd;

                                 cmd->data = NULL;

                                 mmc_wait_for_req(host, &mrq)=> __mmc_start_req(host, mrq)=>mmc_start_request(host, mrq);   

                                           __mmc_start_request(host, mrq);     //mmc/core/core.c

                                                      host->ops->request(host, mrq);     

                          *rocr = cmd.resp[0]                           

                mmc_attach_bus(host, &mmc_ops);         //core/core.c

                        //传进来第2个参数名为ops

                        host->bus_ops = ops;

                        host->bus_refs = 1;

                        host->bus_dead = 0;

                //根据host->ocr_avail屏蔽不支持的电压,选择最低电压

                rocr = mmc_select_voltage(host, ocr);                //core/core.c

                        ocr &= host->ocr_avail;

                        ...

                mmc_init_card(host, rocr, NULL);        //core/mmc.c

                        //struct mmc_card *card;    

                      mmc_go_idle;                     //CMD0    mmc/core/mmc_ops.c

                      mmc_send_op_cond;       //CMD1    mmc/core/mmc_ops.c

                      mmc_all_send_cid;           //CMD2    mmc/core/mmc_ops.c

                      mmc_set_relative_addr;   //CMD3    mmc/core/mmc_ops.c

                      mmc_send_csd;                //CMD9    mmc/core/mmc_ops.c

                      mmc_decode_csd(card);  //               mmc/core/mmc.c

                      mmc_decode_cid(card);   //               mmc/core/mmc.c

                      mmc_select_card;              //CMD7    mmc/core/mmc_ops.c

                      mmc_read_ext_csd(card);  //             mmc/core/mmc.c

                             mmc_decode_ext_csd(card, ext_csd)        //mmc/core/mmc.c

                                     mmc_select_card_type(card);        //mmc/core/mmc.c

                                            根据​caps的速度模式和extcsd读出的数据​确定类型

                      读写erase_size(依赖于CID和Extended CSD)

                      //切换分区

                      mmc_switch(card, ..., EXT_CSD_PART_CONFIG, ...)         //CMD6    mmc/core/mmc_ops.c

                      mmc_select_timing(card) //mmc/core/mmc.c

                            //SWITCH命令号:6

                            mmc_select_hs400es/mmc_select_hs200/mmc_select_hs     //mmc/core/mmc.c

                                  前两个:

                                          设置host:电压、driver_strength、driver_type、bus_width(mmc_switch成功则设置host的)

                                          设置timing:__mmc_switch成功则设置host的

                                  第三个:直接__mmc_switch到高速模式。

                            mmc_set_bus_speed(card);                                 //mmc/core/mmc.c

                                   //​设置时钟频率

                                   mmc_set_clock(card->host, max_dtr);          //mmc/core/core.c

                                           如果频率小于等于maxhost->f_max(设备树max_frequency指定),则设置。

                                           否则设为设备树指定的。

                                           mmc_set_ios(host);       //mmc/core/core.c

                                                //参数类型为struct mmc_host *

                                                struct mmc_ios *ios = &host->ios;

                                                pr_debug("%s: clock %uHz busmode %u powermode %u cs %u Vdd %u "

                                                    "width %u timing %u\n", mmc_hostname(host), ios->clock, ios->bus_mode,

                                                     ios->power_mode, ios->chip_select, ios->vdd, 1 << ios->bus_width, ios->timing);

                                                打印示例:mmc0: clock 25000000Hz busmode 2 powermode 2 cs 0 Vdd 21 width 1 timing 2

                                                host->ops->set_ios(host, ios);

                      mmc_card_hs200(card)                   //include/linux/mmc/mmc.h

                              return card->host->ios.timing == MMC_TIMING_MMC_HS200;

                      //如果上边返回1,则执行下边的。//到###

                      mmc_hs200_tuning(card)                 //mmc/core/mmc.c

                              若有host->ops->prepare_hs400_tuning则执行

                              mmc_execute_tuning(card)      //mmc/core/core.c

                                      ​host->ops->execute_tuning​(host, opcode)

                      mmc_select_hs400(card)                  //mmc/core/mmc.c

                              __mmc_switch到HS的timing,成功则mmc_set_ios切换host的timing到HS。

                              __mmc_switch到8 bit DDR(dual data rate)

                              __mmc_switch到HS400的timing,成功则mmc_set_ios切换host的timing到HS400。

                              mmc_set_bus_speed(card);       //mmc/core/mmc.c

                                      mmc_set_ios设置尽量高的频率  //mmc/core/core.c

                                      //频率不会超过host->f_max(即设备树的max_frequency项)          ​###

                        否则

                        mmc_select_bus_width(card);                   //mmc/core/mmc.c

                                // 依次尝试设为8bit,4bit,1bit

                                先mmc_switch()发送CMD6,设置​外设位宽​(EXT_CSD寄存器)

                                若成功则设置​hos​t的。mmc_set_bus_width=> mmc_set_ios(host)=> 

                        card = mmc_alloc_card(host, &mmc_type);

                                        card->dev.bus = &mmc_bus_type;

                                        card->dev.type = type;

                        card->ocr = ocr;

                        card->type = MMC_TYPE_MMC;

                        card->rca = 1;

                        host->card = card;


                mmc_add_card(host->card);                                                                //core/bus.c

                        switch (card->type) {

                                case MMC_TYPE_MMC:

                                        type = "MMC";

                                ...

                        }

                        确定uhs_bus_speed_mode(根据card->host->ios.timing)

                        ​pr_info​("%s: new %s%s%s%s%s%s card at address %04x\n",

                                                        mmc_hostname(card->host),

                                                        mmc_card_uhs(card) ? "ultra high speed " :

                                                        (mmc_card_hs(card) ? "high speed " : ""),

                                                        mmc_card_hs400(card) ? "HS400 " :

                                                        (mmc_card_hs200(card) ? "HS200 " : ""),

                                                        mmc_card_hs400es(card) ? "Enhanced strobe " : "",

                                                        mmc_card_ddr52(card) ? "DDR " : "",

                                                        uhs_bus_speed_mode, type, card->rca);

                        device_add(&card->dev)                                                        //base/core.c

                                先调用mmc_bus_type的match函数         //此函数直接返回1。

                                        //device_add=> bus_probe_device中有个if (bus->p->drivers_autoprobe),

                                        //这个是在core/bus.c=>mmc_register_bus函数里指定的

                                match成功,调用mmc_bus_type的probe函数

                                        会调用driver->probe => mmc_driver.probe //card/block.c

                                        mmc_blk_probe                //card/block.c          详细流程见下边

                                        //driver->probe对应mmc_driver.probe原因:

                                        //card/block.c=>mmc_blk_init => mmc_register_driver(&mmc_driver);

                        mmc_card_set_present(card);                      //include/linux/mmc/card.h

                                card->state |= MMC_STATE_PRESENT;

                        mmc_claim_host(host);                                   //mmc/core.h

mmc_blk_probe

mmc_blk_probe            //card/block.c

        struct mmc_blk_data *md, *part_md;

        char cap_str[10];

        md = mmc_blk_alloc(card);                         //card/block.c

                mmc_blk_alloc_req(card, &card->dev, size, false, NULL, MMC_BLK_DATA_AREA_MAIN);    //card/block.c

                            //传进来第1个参数名为card

                            struct mmc_blk_data *md;

                            md = kzalloc(sizeof(struct mmc_blk_data), GFP_KERNEL);

                            md->disk = alloc_disk(perdev_minors);

                            mmc_init_queue(&md->queue, card, &md->lock, subname);        //card/queue.c

                                        //传进来第1个参数名为mq,第2个为card

                                        blk_queue_prep_rq(mq->queue, mmc_prep_request);

                                        //分配max_segs个scatterlist用于request请求

                                        //(只是分配scatterlist,并未分配存放数据的内存)

                                        mqrq_cur->sg = mmc_alloc_sg(host->max_segs, &ret);

                                        mqrq_prev->sg = mmc_alloc_sg(host->max_segs, &ret);

                                        //起一个kennel thread运行mmc_queue_thread来处理上层发送下来的request,

                                        //对每个reqeust执行issue_fn回调

                                        //注意:issue_fn回调在下边指定为mmc_blk_issure_req。

                                        //mmc_blk_issue_rq是具体的mmc request处理函数。

                                        mq->thread = kthread_run(mmc_queue_thread, mq, "mmcqd/%d%s",

                                                                                        host->index, subname ? subname : "");

                            //MMC_BLOCK_MAJOR是179

                            md->disk->major    = MMC_BLOCK_MAJOR;

                            snprintf(md->disk->disk_name, sizeof(md->disk->disk_name),

                                          "mmcblk%u%s", card->host->index, subname ? subname : "");

        获得容量:从md->disk中获得容量,写到cap_str

        打印:pr_info("%s: %s %s %s %s\n",   md->disk->disk_name,

                      mmc_card_id(card), mmc_card_name(card), cap_str, md->read_only ? "(ro)" : "");

                //打印示例:mmcblk2: mmc2:0001 8GME4R 7.28 GiB

        mmc_blk_alloc_parts(card, md)                                            //card/block.c

                        对于小于card->nr_parts的每一个card->part[idx]              //这些是boot、general、user data等分区

                        mmc_blk_alloc_part(card, md, ...);                //card/block.c

                                struct mmc_blk_data *part_md;

                                part_md = mmc_blk_alloc_req(card, disk_to_dev(md->disk),...);         //card/block.c

                                        //传进来第2个参数名为parent

                                        md->disk = alloc_disk(perdev_minors);

                                        md->parent = parent;

                                        mmc_init_queue(&md->queue, card, &md->lock, subname);

                                        snprintf(md->disk->disk_name, sizeof(md->disk->disk_name),

                                                 "mmcblk%u%s", card->host->index, subname ? subname : "");

                                list_add(&part_md->part, &md->part);

                                打印:pr_info("%s: %s %s partition %u %s\n", part_md->disk->disk_name,

                                              mmc_card_id(card), mmc_card_name(card), part_md->part_type, cap_str)

                                        //打印示例:mmcblk2boot0: mmc2:0001 8GME4R partition 1 4.00 MiB

        mmc_add_disk(md)                     //mmc/card/block.c

                device_add_disk(md->parent, md->disk);      //block/partitions/genhd.c

        list_for_each_entry(part_md, &md->part, part) {

                mmc_add_disk(part_md)

mmc_attach_sd流程

mmc_attach_sd                //mmc/core/sd.c

        //命令号:41

        mmc_send_app_op_cond(host, 0, &ocr);        //mmc/core/sd_ops.c

        rocr = mmc_select_voltage(host, ocr);        //mmc/core/core.c

                //屏蔽不支持的电压,选择最小电压

        ​mmc​_sd_init_card(host, rocr, NULL);                //mmc/core/sd.c

                //第一个参数类型为mmc_host

                mmc_sd_get_cid(host, ocr, cid, &rocr);        //mmc/core/sd.c

                        mmc_go_idle(host);

                        //命令号:8 (为兼容SD2.0,发命令41之前必须发命令8)

                        mmc_send_if_cond(host, ocr);

                        //命令号:41

                        mmc_send_app_op_cond(host, ocr, rocr);

                        mmc_all_send_cid(host, cid);


                if (host->ops->init_card)

                        host->ops->init_card(host, card);

                mmc_send_relative_addr(host, &card->rca);        //mmc/core/sd_ops.c

                mmc_sd_get_csd(host, card);                                        //mmc/core/sd.c

                mmc_select_card(card);                                                //mmc/core/mmc_ops.c

                mmc_sd_setup_card(host, card, oldcard != NULL);                //mmc/core/sd.c

                //命令号:6

                mmc_sd_switch_hs(card);                                                //mmc/core/sd.c

                mmc_set_timing(card->host, MMC_TIMING_SD_HS);        //mmc/core/core.c

                        host->ios.timing = timing;

                        mmc_set_ios(host);                        //mmc/core/core.c

                                struct mmc_ios *ios = &host->ios;

                                pr_debug("%s: clock %uHz busmode %u powermode %u cs %u Vdd %u "

                                         "width %u timing %u\n", mmc_hostname(host), ios->clock, ios->bus_mode,

                                           ios->power_mode, ios->chip_select, ios->vdd, 1 << ios->bus_width, ios->timing);

                                 打印示例:mmc0: clock 25000000Hz busmode 2 powermode 2 cs 0 Vdd 21 width 1 timing 2

                                 host->ops->set_ios(host, ios);


                mmc_set_clock(host, mmc_sd_get_max_clock(card));        //mmc/core/core.c

                        if (hz > host->f_max)

                                hz = host->f_max;

                        host->ios.clock = hz;

                        mmc_set_ios(host);                                //mmc/core/core.c

                //先发命令55,后发送命令6

                mmc_app_set_bus_width(card, MMC_BUS_WIDTH_4);                //mmc/core/sd_ops.c

                mmc_set_bus_width(host, MMC_BUS_WIDTH_4);                        //mmc/core/core.c

                        host->ios.bus_width = width;

                        mmc_set_ios(host);                                //mmc/core/core.c

        ​mmc​_add_card(host->card);    //mmc/core/bus.c

            pr_info("%s: new %s%s%s%s%s%s card at address %04x\n",

                    mmc_hostname(card->host),

                    mmc_card_uhs(card) ? "ultra high speed " :

                    (mmc_card_hs(card) ? "high speed " : ""),

                    mmc_card_hs400(card) ? "HS400 " :

                    (mmc_card_hs200(card) ? "HS200 " : ""),

                    mmc_card_hs400es(card) ? "Enhanced strobe " : "",

                    mmc_card_ddr52(card) ? "DDR " : "",

                    uhs_bus_speed_mode, type, card->rca);

            打印示例:mmc0: new high speed SDXC card at address 59b4

打印分区信息流程

device_add_disk         //block/partitions/genhd.c

        register_disk(parent, disk);    //block/partitions/genhd.c

                blkdev_get(bdev, FMODE_READ, NULL);   //fs/block_dev.c

                        __blkdev_get(bdev, mode, 0);  //fs/block_dev.c

                                rescan_partitions(disk, bdev);  //block/partitions-generic.c

                                        check_partition(disk, bdev)   //block/partions/check.c

                                                printk(KERN_INFO "%s", state->pp_buf)

打印示例:mmcblk0: p1(bld) p2(env) p3(kernel) p4(fs)

设备树速度模式


设备树



host成员



硬件模式



最大速度宏



宏对应的值



cap-mmc-highspeed



MMC_CAP_MMC_HIGHSPEED



HS_26

HS_52



MMC_HIGH_26_MAX_DTR

MMC_HIGH_52_MAX_DTR



26M

52M



mmc-ddr-1_8v



MMC_CAP_1_8V_DDR



DDR_1_8V



MMC_HIGH_DDR_MAX_DTR



52M



mmc-ddr-1_2v



MMC_CAP_1_2V_DDR



DDR_1_2V



MMC_HIGH_DDR_MAX_DTR



52M



mmc-hs200-1_8v



MMC_CAP2_HS200_1_8V_SDR



HS200_1_8V



MMC_HS200_MAX_DTR



200M



mmc-hs200-1_2v



MMC_CAP2_HS200_1_2V_SDR



HS200_1_2V



MMC_HS200_MAX_DTR



200M



mmc-hs400-1_8v



MMC_CAP2_HS400_1_8V

MMC_CAP2_HS200_1_8V_SDR



HS400_1_8V



MMC_HS200_MAX_DTR



200M



mmc-hs400-1_2v



MMC_CAP2_HS400_1_2V

MMC_CAP2_HS200_1_2V_SDR



HS400_1_2V



MMC_HS200_MAX_DTR



200M



mmc-hs400-enhanced-strobe



MMC_CAP2_HS400_ES



HS400ES








源码位置​:

myhost_mmc_probe                //mmc/host/myhost_mmc.c

  mmc_rescan                    //core/core.c

    mmc_rescan_try_freq(host, max(freqs[i], host->f_min) //mmc/core/core.c

      mmc_attach_mmc(host)      //mmc/core/mmc.c

        mmc_init_card(host, rocr, NULL);        //mmc/core/mmc.c

          mmc_read_ext_csd(card);               //mmc/core/mmc.c

            mmc_get_ext_csd(card, &ext_csd);    //mmc/core/mmc_ops.c

            mmc_decode_ext_csd(card, ext_csd);  //mmc/core/mmc.c

              mmc_select_card_type(card);       //mmc/core/mmc.c

reboot调用到的流程

调用流程

mmc_bus_shutdown            //mmc/core/bus.c

    struct mmc_host *host = card->host;

    host->bus_ops->shutdown(host)

        mmc_shutdown        //mmc/core/mmc.c

shutdown函数注册流程

mmc_init        //mmc/core/core.c

    mmc_register_bus()        //mmc/core/bus.c

        bus_register(&mmc_bus_type)        //mmc_bus_type.shutdown    = mmc_bus_shutdown


mmc_attach_mmc(host) //mmc/core/mmc.c

    //mmc_ops在mmc/core/mmc.c定义

    mmc_attach_bus(host, &mmc_ops);        //mmc/core/core.c

        host->bus_ops = ops;        //mmc_ops.shutdown = mmc_shutdown;