码迷,mamicode.com
首页 > 其他好文 > 详细

EMMC架构

时间:2016-09-02 21:57:42      阅读:552      评论:0      收藏:0      [点我收藏+]

标签:

现在EMMC盛行,分析总结还是很有必要的。以下以全志a64为实例切入主题。

这里a64有三个sdc0~2,硬件上sdc2是连接EMMC,这里只分析sdc2的代码。


初始化的代码在linux-3.10/drivers/mmc/host/sunxi-mmc.c
以下忽略部分冗余代码:

 1 static const struct of_device_id sunxi_mmc_of_match[] = {
 2     ......
 3     ......
 4     { .compatible = "allwinner,sun50i-sdmmc2", },
 5     ......
 6     ......
 7 };
 8 MODULE_DEVICE_TABLE(of, sunxi_mmc_of_match);
 9 
10 static struct platform_driver sunxi_mmc_driver = {
11     .driver = {
12         .name    = "sunxi-mmc",
13         .of_match_table = of_match_ptr(sunxi_mmc_of_match),
14         .pm = sunxi_mmc_pm_ops,
15     },
16     .probe        = sunxi_mmc_probe,
17     .remove        = sunxi_mmc_remove,
18     .shutdown   = sunxi_shutdown_mmc,
19 };
20 module_platform_driver(sunxi_mmc_driver);

 

设备树会初始化deivce,这里有driver,下面直接进sunxi_mmc_probe分析。
以下忽略部分冗余代码:

 1 static int sunxi_mmc_probe(struct platform_device *pdev)
 2 {
 3     struct sunxi_mmc_host *host;    //全志a64主控硬件相关
 4     struct mmc_host *mmc;    //emmc架构相关
 5     int ret;
 6 
 7     dev_info(&pdev->dev,"%s\n",DRIVER_VERSION);
 8 
 9     mmc = mmc_alloc_host(sizeof(struct sunxi_mmc_host), &pdev->dev);    //初始化mmc_host,后面会分析
10 
11     host = mmc_priv(mmc);    //host = mmc->private;
12     host->mmc = mmc;        //sunxi_mmc_host和mmc_host建立纽带
13 
14     //配置硬件相关,如时钟,sdc控制寄存器,IO复用,中断,电源控制
15     ret = sunxi_mmc_resource_request(host, pdev);    
16 
17     //初始化dma     #define     4*PAGE_SIZE
18     host->dma_mask = DMA_BIT_MASK(32);
19     pdev->dev.dma_mask = &host->dma_mask;
20     pdev->dev.coherent_dma_mask = DMA_BIT_MASK(32);
21     host->sg_cpu = dma_alloc_coherent(&pdev->dev, SUNXI_REQ_PAGE_SIZE,
22                       &host->sg_dma, GFP_KERNEL);    
23 
24     mmc->ops        = &sunxi_mmc_ops;
25     mmc->max_blk_count    = 8192;
26     mmc->max_blk_size    = 4096;
27     mmc->max_segs        = SUNXI_REQ_PAGE_SIZE / sizeof(struct sunxi_idma_des);
28     mmc->max_seg_size    = (1 << host->idma_des_size_bits);
29     mmc->max_req_size    = mmc->max_seg_size * mmc->max_segs;
30     /* 400kHz ~ 50MHz */
31     mmc->f_min        =   400000;
32     mmc->f_max        = 50000000;
33     mmc->caps           |= MMC_CAP_MMC_HIGHSPEED | MMC_CAP_SD_HIGHSPEED | MMC_CAP_ERASE 34                         | MMC_CAP_WAIT_WHILE_BUSY;
35     //mmc->caps2      |= MMC_CAP2_HS400_1_8V;
36 
37 
38     mmc_of_parse(mmc);    //解析设备树相关的信息
39 
40     ret = mmc_add_host(mmc);    //重点,真正初始化emmc并启动,后面会分析
41 
42     ret = mmc_create_sys_fs(host,pdev);
43     
44     dev_info(&pdev->dev, "base:0x%p irq:%u\n", host->reg_base, host->irq);
45     platform_set_drvdata(pdev, mmc);
46     return 0;
47 }

到此probe结束,有两个比较关键的函数mmc_alloc_host和mmc_add_host,真正启动emmc的操作都在这里
mmc_alloc_host和mmc_add_host的代码在linux-3.10/drivers/mmc/core/host.c
以下忽略部分冗余代码:

 1 struct mmc_host *mmc_alloc_host(int extra, struct device *dev)
 2 {
 3     int err;
 4     struct mmc_host *host;
 5 
 6     host = kzalloc(sizeof(struct mmc_host) + extra, GFP_KERNEL);
 7 
 8     /* scanning will be enabled when we‘re ready */
 9     host->rescan_disable = 1;
10     idr_preload(GFP_KERNEL);    
11     
12     err = idr_alloc(&mmc_host_idr, host, 0, 0, GFP_NOWAIT);    
13     if (err >= 0)
14         host->index = err;    //通过整数id管理地址,具体细节本人不太清楚
15 
16     idr_preload_end();
17 
18     dev_set_name(&host->class_dev, "mmc%d", host->index);
19 
20     host->parent = dev;
21     host->class_dev.parent = dev;
22     host->class_dev.class = &mmc_host_class;
23     device_initialize(&host->class_dev);
24 
25     mmc_host_clk_init(host);    //这里初始化框架相关的clock,不涉及硬件
26 
27     host->slot.cd_irq = -EINVAL;
28 
29     init_waitqueue_head(&host->wq);
30     wake_lock_init(&host->detect_wake_lock, WAKE_LOCK_SUSPEND,    //初始化唤醒内核的锁
31         kasprintf(GFP_KERNEL, "%s_detect", mmc_hostname(host)));
32     INIT_DELAYED_WORK(&host->detect, mmc_rescan);        //重要,初始化检查card的队列
33 
34     host->pm_notify.notifier_call = mmc_pm_notify;
35     /*
36      * By default, hosts do not support SGIO or large requests.
37      * They have to set these according to their abilities.
38      */
39     host->max_segs = 1;
40     host->max_seg_size = PAGE_CACHE_SIZE;    //#define  PAGE_CACHE_SIZE    1UL << 16
41 
42     host->max_req_size = PAGE_CACHE_SIZE;
43     host->max_blk_size = 512;
44     host->max_blk_count = PAGE_CACHE_SIZE / 512;
45 
46     return host;
47 }    
48 
49 int mmc_add_host(struct mmc_host *host)
50 {
51     int err;
52 
53     err = device_add(&host->class_dev);
54 
55     led_trigger_register_simple(dev_name(&host->class_dev), &host->led);    //;类似硬盘的LED闪烁
56 
57 #ifdef CONFIG_DEBUG_FS
58     mmc_add_host_debugfs(host);    //debug用
59 #endif
60     mmc_host_clk_sysfs_init(host);
61 
62     mmc_start_host(host);    //重要,真正操作都在这里
63 
64     return 0;
65 }

 

mmc_start_host的代码在linux-3.10/drivers/mmc/core/core.c
以下忽略部分冗余代码:

void mmc_start_host(struct mmc_host *host)
{
    host->f_init = max(freqs[0], host->f_min);    //初始时钟
    host->rescan_disable = 0;    //开启rescan
    mmc_power_up(host);
    mmc_detect_change(host, 0);
}

static void mmc_power_up(struct mmc_host *host)
{
    int bit;

    if (host->ios.power_mode == MMC_POWER_ON)    //已经启动
        return;

    mmc_host_clk_hold(host);    //没有定义CONFIG_MMC_CLKGATE 所有gateclock相关都是空操作

    /* If ocr is set, we use it */
    if (host->ocr)    //ocr是电源配置,在sunxi_mmc_resource_request已经设置好
        bit = ffs(host->ocr) - 1;
    else
        bit = fls(host->ocr_avail) - 1;
    //io bus设置
    host->ios.vdd = bit;
    if (mmc_host_is_spi(host))
        host->ios.chip_select = MMC_CS_HIGH;
    else
        host->ios.chip_select = MMC_CS_DONTCARE;
    host->ios.bus_mode = MMC_BUSMODE_PUSHPULL;
    host->ios.power_mode = MMC_POWER_UP;    //上电状态
    host->ios.bus_width = MMC_BUS_WIDTH_1;
    host->ios.timing = MMC_TIMING_LEGACY;
    mmc_set_ios(host);    //一开始用单线模式初始化,最终调用sunxi_mmc_set_ios,设置线宽,总线,时序

    /* Set signal voltage to 3.3V */
    __mmc_set_signal_voltage(host, MMC_SIGNAL_VOLTAGE_330);    //最终调用sunxi_mmc_signal_voltage_switch

    /*
     * This delay should be sufficient to allow the power supply
     * to reach the minimum voltage.
     */
    mmc_delay(10);

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

    host->ios.power_mode = MMC_POWER_ON;    //工作状态
    mmc_set_ios(host);

    /*
     * This delay must be at least 74 clock sizes, or 1 ms, or the
     * time required to reach a stable voltage.
     */
    mmc_delay(10);

    mmc_host_clk_release(host);    //没有定义CONFIG_MMC_CLKGATE 所有gateclock相关都是空操作
}

void mmc_detect_change(struct mmc_host *host, unsigned long delay)
{
    host->detect_change = 1;

    //wake_lock(&host->detect_wake_lock);
    if(!(host->caps&MMC_CAP_NEEDS_POLL))
        wake_lock(&host->detect_wake_lock);    //唤醒内核
    mmc_schedule_delayed_work(&host->detect, delay);    //主动执行队列mmc_rescan
}

初始化emmc的程序已经完成,如果是sd卡,会中断或者查询方法调用检测sd卡的程序。

mmc_set_ios这个函数很重要,改变emmc的配置都在这里,会调用硬件底层相关函数。

emmc直接主动调用mmc_rescan。

以下忽略部分冗余和大量无关的逻辑判断的代码:

 1 void mmc_rescan(struct work_struct *work)
 2 {
 3     struct mmc_host *host = container_of(work, struct mmc_host, detect.work);
 4     int i;
 5     bool extend_wakelock = false;
 6     bool present         = false;
 7 
 8     if (host->rescan_disable)    //rescan_disable = 0
 9         return;
10 
11     /* If there is a non-removable card registered, only scan once */
12     if ((host->caps & MMC_CAP_NONREMOVABLE) && host->rescan_entered){
13         wake_unlock(&host->detect_wake_lock);
14         return;
15     }
16 
17     host->rescan_entered = 1;
18 
19     host->detect_change = 0;
20 
21 
22     mmc_claim_host(host);    
23     for (i = 0; i < ARRAY_SIZE(freqs); i++) {
24         if (!mmc_rescan_try_freq(host, max(freqs[i], host->f_min))) {
25             extend_wakelock = true;    //mmc_rescan_try_freq真正的初始化
26             present = true;
27             break;        //初始化成功立刻跳出        
28         }
29         if (freqs[i] <= host->f_min)
30             break;
31     }
32     mmc_release_host(host);
33 
34     if (extend_wakelock)
35         wake_lock_timeout(&host->detect_wake_lock, HZ / 2);
36     else
37         wake_unlock(&host->detect_wake_lock);
38 }

 

核心函数是mmc_rescan_try_freq,里面做了什么?

 1 static int mmc_rescan_try_freq(struct mmc_host *host, unsigned freq)
 2 {
 3     host->f_init = freq;
 4 
 5     mmc_power_up(host); 
 6 
 7     /*
 8      * Some eMMCs (with VCCQ always on) may not be reset after power up, so
 9      * do a hardware reset if possible.
10      */
11     mmc_hw_reset_for_init(host);    //硬件复位,调用mmc_host_ops.hw_reset = sunxi_mmc_hw_reset
12 
13     mmc_go_idle(host);    //使mmc空闲
14 
15     mmc_send_if_cond(host, host->ocr_avail);
16 
17     /* Order‘s important: probe SDIO, then SD, then MMC */
18     if (!mmc_attach_sdio(host))    //不是sdio,不会响应对应命令
19         return 0;
20     if (!mmc_attach_sd(host))    //不是sd,不会响应对应命令
21         return 0;
22     if (!mmc_attach_mmc(host))    //zho真正attach对应的emmc
23         return 0;
24 
25     mmc_power_off(host);
26     return -EIO;
27 }

 

mmc_attach_mmc的代码在linux-3.10/drivers/mmc/core/mmc.c
以下忽略部分冗余和大量无关的逻辑判断的代码:

  1 int mmc_attach_mmc(struct mmc_host *host)
  2 {
  3     int err;
  4     u32 ocr;
  5 
  6     mmc_set_bus_mode(host, MMC_BUSMODE_OPENDRAIN);    //bus开漏
  7 
  8     err = mmc_send_op_cond(host, 0, &ocr);    //配置ocr电源状态
  9 
 10     mmc_attach_bus_ops(host);    //设置bus_ops,mmc_bus_ops = mmc_ops_unsafe
 11 
 12 
 13     host->ocr = mmc_select_voltage(host, ocr);
 14 
 15     /*
 16      * Detect and init the card.
 17      */
 18     err = mmc_init_card(host, host->ocr, NULL);
 19 
 20     mmc_release_host(host);
 21     err = mmc_add_card(host->card);
 22     mmc_claim_host(host);
 23     return 0;
 24 
 25 }
 26 
 27 static int mmc_init_card(struct mmc_host *host, u32 ocr,
 28     struct mmc_card *oldcard)
 29 {
 30     struct mmc_card *card;
 31     int err, ddr = 0;
 32     u32 cid[4];
 33     unsigned int max_dtr;
 34     u32 rocr;
 35     u8 *ext_csd = NULL;
 36 
 37 
 38     mmc_set_bus_mode(host, MMC_BUSMODE_OPENDRAIN);
 39 
 40     /*
 41      * Since we‘re changing the OCR value, we seem to
 42      * need to tell some cards to go back to the idle
 43      * state.  We wait 1ms to give cards time to
 44      * respond.
 45      * mmc_go_idle is needed for eMMC that are asleep
 46      */
 47     mmc_go_idle(host);
 48 
 49     /* The extra bit indicates that we support high capacity */
 50     err = mmc_send_op_cond(host, ocr | (1 << 30), &rocr);    //识别大容量
 51 
 52     /*
 53      * Fetch CID from card.
 54      */
 55     err = mmc_all_send_cid(host, cid);    //识别card id
 56 
 57     /*
 58      * Allocate card structure.
 59      */
 60     card = mmc_alloc_card(host, &mmc_type);    //重要,后续分析
 61 
 62 
 63     card->type = MMC_TYPE_MMC;
 64     card->rca = 1;
 65     memcpy(card->raw_cid, cid, sizeof(card->raw_cid));
 66     
 67     /*
 68      * For native busses:  set card RCA and quit open drain mode.
 69      */
 70 
 71     err = mmc_set_relative_addr(card);
 72 
 73     mmc_set_bus_mode(host, MMC_BUSMODE_PUSHPULL);
 74 
 75     /*
 76      * Fetch CSD from card.
 77      */
 78     err = mmc_send_csd(card, card->raw_csd);
 79 
 80     err = mmc_decode_csd(card);
 81 
 82     err = mmc_decode_cid(card);
 83     
 84     /*
 85      * Select card, as all following commands rely on that.
 86      */
 87 
 88     err = mmc_select_card(card);
 89 
 90     /*
 91      * Fetch and process extended CSD.
 92      */
 93 
 94     err = mmc_get_ext_csd(card, &ext_csd);
 95 
 96     err = mmc_read_ext_csd(card, ext_csd);
 97 
 98     /* If doing byte addressing, check if required to do sector
 99      * addressing.  Handle the case of <2GB cards needing sector
100      * addressing.  See section 8.1 JEDEC Standard JED84-A441;
101      * ocr register has bit 30 set for sector addressing.
102      */
103     if (!(mmc_card_blockaddr(card)) && (rocr & (1<<30)))
104         mmc_card_set_blockaddr(card);
105 
106     /* Erase size depends on CSD and Extended CSD */
107     mmc_set_erase_size(card);
108 
109     /*
110      * Activate high speed (if supported)
111      */
112     if (card->ext_csd.hs_max_dtr != 0) {
113         err = 0;
114         if (card->ext_csd.hs_max_dtr > 52000000 &&
115             host->caps2 & MMC_CAP2_HS200)
116             err = mmc_select_hs200(card);
117         else if    (host->caps & MMC_CAP_MMC_HIGHSPEED)
118             //err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
119             //         EXT_CSD_HS_TIMING, 1,
120             //         card->ext_csd.generic_cmd6_time);
121             err = __mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
122                    EXT_CSD_HS_TIMING, 1,
123                    card->ext_csd.generic_cmd6_time,
124                    true, true, true);
125 
126         if (card->ext_csd.hs_max_dtr > 52000000 &&
127             host->caps2 & MMC_CAP2_HS200) {
128             mmc_card_set_hs200(card);
129             mmc_set_timing(card->host,
130                        MMC_TIMING_MMC_HS200);
131         } else {
132             mmc_card_set_highspeed(card);
133             mmc_set_timing(card->host, MMC_TIMING_MMC_HS);
134         }        
135     }
136 
137     /*
138      * Compute bus speed.
139      */
140     max_dtr = (unsigned int)-1;
141 
142     if (mmc_card_highspeed(card) || (mmc_card_hs200(card)|| mmc_card_hs400(card))) {
143         if (max_dtr > card->ext_csd.hs_max_dtr)
144             max_dtr = card->ext_csd.hs_max_dtr;
145         if (mmc_card_highspeed(card) && (max_dtr > 52000000))
146             max_dtr = 52000000;
147     } else if (max_dtr > card->csd.max_dtr) {
148         max_dtr = card->csd.max_dtr;
149     }
150 
151     mmc_set_clock(host, max_dtr);    
152     //mmc_set_ios(host)一开始用单线模式初始化,最终调用sunxi_mmc_set_ios
153     //设置线宽,总线,时序
154 
155     /*
156      * Indicate HS200 SDR mode (if supported).
157      */
158     if (mmc_card_hs200(card)) {
159         u32 ext_csd_bits;
160         u32 bus_width = card->host->ios.bus_width;
161 
162 
163         if(host->caps2 & MMC_CAP2_HS400){
164             //pr_info("************%s: %s,%d************\n",
165             //    mmc_hostname(card->host),__FUNCTION__,__LINE__);
166             err =  mmc_select_hs400(card);
167         }
168 
169 
170         if(mmc_card_hs400(card)){    
171             ext_csd_bits = EXT_CSD_DDR_BUS_WIDTH_8;
172             err = mmc_select_powerclass(card, ext_csd_bits, ext_csd);    //配置mmc电源
173         }else{
174             ext_csd_bits = (bus_width == MMC_BUS_WIDTH_8) ?
175                     EXT_CSD_BUS_WIDTH_8 : EXT_CSD_BUS_WIDTH_4;
176             err = mmc_select_powerclass(card, ext_csd_bits, ext_csd);
177         }
178     }
179 
180     /*
181      * Enable HPI feature (if supported)
182      */
183     if (card->ext_csd.hpi) {
184         err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
185                 EXT_CSD_HPI_MGMT, 1,
186                 card->ext_csd.generic_cmd6_time);
187 
188     
189         card->ext_csd.hpi_en = 1;
190     }
191 
192     host->card = card;
193 
194     mmc_free_ext_csd(ext_csd);
195     return 0;
196 }

调用完mmc_attach_mmc,card和host已经准备就绪,怎么通知drv呢?当然需要device!

剩下mmc_alloc_card和mmc_add_card没有分析完,代码都在linux-3.10/drivers/mmc/core/bus.c
以下忽略部分冗余代码:

  1 struct mmc_card *mmc_alloc_card(struct mmc_host *host, struct device_type *type)
  2 {
  3     struct mmc_card *card;
  4 
  5     card = kzalloc(sizeof(struct mmc_card), GFP_KERNEL);
  6     if (!card)
  7         return ERR_PTR(-ENOMEM);
  8 
  9     card->host = host;
 10 
 11     device_initialize(&card->dev);
 12 
 13     card->dev.parent = mmc_classdev(host);
 14     card->dev.bus = &mmc_bus_type;    //dev.bus,device_attach优先选择bus->probe
 15     card->dev.release = mmc_release_card;
 16     card->dev.type = type;
 17 
 18     return card;
 19 }
 20 
 21 /*
 22  * This currently matches any MMC driver to any MMC card - drivers
 23  * themselves make the decision whether to drive this card in their
 24  * probe method.
 25  */
 26 static int mmc_bus_match(struct device *dev, struct device_driver *drv)
 27 {
 28     return 1;    //只要在这个总线就匹配成功
 29 }
 30 
 31 static int mmc_bus_probe(struct device *dev)
 32 {
 33     struct mmc_driver *drv = to_mmc_driver(dev->driver);
 34     struct mmc_card *card = mmc_dev_to_card(dev);
 35 
 36     return drv->probe(card);
 37 }
 38 
 39 static struct bus_type mmc_bus_type = {
 40     .name        = "mmc",
 41     .dev_attrs    = mmc_dev_attrs,
 42     .match        = mmc_bus_match,
 43     .uevent        = mmc_bus_uevent,
 44     .probe        = mmc_bus_probe,
 45     .remove        = mmc_bus_remove,
 46     .pm        = &mmc_bus_pm_ops,
 47 };
 48 
 49 int mmc_register_bus(void)    //在linux-3.10/drivers/mmc/core/core.c里subsys_initcall(mmc_init)被调用
 50 {
 51     return bus_register(&mmc_bus_type);
 52 }
 53 
 54 int mmc_add_card(struct mmc_card *card)
 55 {
 56     int ret;
 57     const char *type;
 58     const char *uhs_bus_speed_mode = "";
 59     static const char *const uhs_speeds[] = {
 60         [UHS_SDR12_BUS_SPEED] = "SDR12 ",
 61         [UHS_SDR25_BUS_SPEED] = "SDR25 ",
 62         [UHS_SDR50_BUS_SPEED] = "SDR50 ",
 63         [UHS_SDR104_BUS_SPEED] = "SDR104 ",
 64         [UHS_DDR50_BUS_SPEED] = "DDR50 ",
 65     };
 66 
 67     dev_set_name(&card->dev, "%s:%04x", mmc_hostname(card->host), card->rca);
 68 
 69     switch (card->type) {
 70     case MMC_TYPE_MMC:
 71         type = "MMC";
 72         break;
 73     ....
 74     ....
 75     default:
 76         type = "?";
 77         break;
 78     }
 79 
 80     if (mmc_sd_card_uhs(card) &&
 81         (card->sd_bus_speed < ARRAY_SIZE(uhs_speeds)))
 82         uhs_bus_speed_mode = uhs_speeds[card->sd_bus_speed];
 83 
 84 
 85     pr_info("%s: new %s%s%s%s%s card at address %04x\n",
 86         mmc_hostname(card->host),
 87         mmc_card_uhs(card) ? "ultra high speed " :
 88         (mmc_card_highspeed(card) ? "high speed " : ""),
 89         mmc_card_hs400(card) ? "HS400 " :
 90         (mmc_card_hs200(card) ? "HS200 " : ""),
 91         mmc_card_ddr_mode(card) ? "DDR " : "",
 92         uhs_bus_speed_mode, type, card->rca);
 93     
 94     mmc_init_context_info(card->host);    //emmc队列等信息(block设备会用到)
 95 
 96     ret = device_add(&card->dev);    //等待driver
 97 
 98     mmc_card_set_present(card);
 99 
100     return 0;
101 }
102 
103 /**
104  *    mmc_register_driver - register a media driver
105  *    @drv: MMC media driver
106  */
107 int mmc_register_driver(struct mmc_driver *drv)
108 {
109     drv->drv.bus = &mmc_bus_type;
110     return driver_register(&drv->drv);
111 }

现在device这边已经准备就绪,就差某个drv调用mmc_register_driver进行match,最后调用某个drv->probe。

其实在linux-3.10/drivers/mmc/card/block.c就调用了mmc_register_driver。
以下忽略部分冗余代码:

 1 static struct mmc_driver mmc_driver = {
 2     .drv        = {
 3         .name    = "mmcblk",
 4     },
 5     .probe        = mmc_blk_probe,
 6     .remove        = mmc_blk_remove,
 7     .suspend    = mmc_blk_suspend,
 8     .resume        = mmc_blk_resume,
 9 };
10 
11 static int __init mmc_blk_init(void)
12 {
13     int res;
14 
15     max_devices = 256 / perdev_minors;    //perdev_minors = 8
16 
17     res = register_blkdev(MMC_BLOCK_MAJOR, "mmc");    //注册块设备
18 
19     res = mmc_register_driver(&mmc_driver);    //我们要找的目标函数
20 
21     return 0;
22 }
23 
24 static void __exit mmc_blk_exit(void)
25 {
26     mmc_unregister_driver(&mmc_driver);
27     unregister_blkdev(MMC_BLOCK_MAJOR, "mmc");
28 }
29 
30 module_init(mmc_blk_init);
31 module_exit(mmc_blk_exit);
32 
33 static int mmc_blk_probe(struct mmc_card *card)
34 {
35     struct mmc_blk_data *md, *part_md;
36     char cap_str[10];
37 
38     md = mmc_blk_alloc(card);
39 
40     string_get_size((u64)get_capacity(md->disk) << 9, STRING_UNITS_2,
41             cap_str, sizeof(cap_str));
42     pr_info("%s: %s %s %s %s\n",
43         md->disk->disk_name, mmc_card_id(card), mmc_cardrd_name(card),
44         cap_str, md->read_only ? "(ro)" : "");
45 
46     if (mmc_blk_alloc_parts(card, md))
47         goto out;
48 
49     mmc_set_drvdata(card, md);
50     mmc_fixup_device(card, blk_fixups);
51 
52     mmc_add_disk(md);
53 
54     list_for_each_entry(part_md, &md->part, part) {
55         mmc_add_disk(part_md);
56 
57     }
58     return 0;
59 }

这里暂时没时间分析block.c里面的函数了,是比较复杂。

 

总结emmc初始化流程:

sunxi_mmc_probe---->mmc_alloc_host---->mmc_add_host---->mmc_start_host---->mmc_rescan---->mmc_rescan_try_freq

---->mmc_attach_mmc---->mmc_init_card---->mmc_alloc_card---->mmc_add_card + mmc_blk_init---->mmc_blk_probe......

 

EMMC架构

标签:

原文地址:http://www.cnblogs.com/kevinhwang/p/5835520.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!