Linux EMMC子系统分析-初始化流程
2016-04-12 13:04
2136 查看
最近在解EMMC的一个bug,发现Linux EMMC有点小复杂,先整理个文档出来吧
用的是TI 平台,仅分析MMC,不分析SD和SDIO
2775分配一个workqueue,这个workqueue是专门用来处理card detect的,EMMC因为是unremovable的,所以不需要关注它
2779 注册mmc_bus_type,实现如下:
mmc_init调用时间比较早,会在host驱动初始化之前执行完。
host驱动位置是kernel/drivers/mmc/host/,一般来说都是platform_driver,以omap hsmmc host驱动为例
只需要关注omap_hsmmc_probe即可,当系统匹配到platform_device时,会调用omap_hsmmc_probe,好长的一个函数
omap_hsmmc_gpio_init是card detect和write protect gpio的初始化,Ignore it!!!
mmc作为快设备,最主要的操作就是数据sectors读写,max_segs定义了block设备的request所支持的最大segment
max_blk_count 一个request中所包含的最大block数
其实多少都不重要,反正就是和request相关的一些上限。
MMCCAP_MMC_HIGHSPEED, MMC_CAP_SD_HIGHSPEED MMC_CAP_WAIT_WHILE_BUSY MMC_CAP_ERASE是最基本的能力
MMC_CAP_8_BIT_DATA表示数据总线是多少,EMMC 数据线支持8线,4线和1线。
2742 ~ 2755 通过of系统定义的一些特定能力,当前MMC_CAP_1_8V_DDR,MMC_CAP2_HS200_1_8V_SDR都很常见了。DDR是Double Date Rate的缩写,SDR是Single Data Rate的缩写
自行脑补百度资料DDR SDRAM, EMMC的DDR SDR与之类似。
DDR=Double Data Rate双倍速率同步动态随机存储器。严格的说DDR应该叫DDR SDRAM,人们习惯称为DDR,其中,SDRAM 是Synchronous Dynamic Random Access Memory的缩写,
即同步动态随机存取存储器。而DDR SDRAM是Double Data Rate SDRAM的缩写,是双倍速率同步动态随机存储器的意思。DDR内存是在SDRAM内存基础上发展而来的,仍然沿用SDRAM生产体系,
一个时钟周期内进行两次读/写操作,即在时钟的上升沿和下降沿分别执行一次读/写操作。
因此对于内存厂商而言,只需对制造普通SDRAM的设备稍加改进,即可实现DDR内存的生产,可有效的降低成本。Double Data Rate:与传统的单数据速率相比,DDR技术实现了一个时钟周期内进行两次读/写操作,即在时钟的上升沿和下降沿分别执行一次读/写操作。
注意对于EMMC CMD线来说,是没有DDR SDR说法的,CMD和response只在clock的上升沿传输,参见EMMC spec5.0 section 6.15.1
DMA相关的代码,内核中EMMC驱动必然要使用DMA方式读写数据,
dma_request_slave_channel_compat分配一个DMA channel
mmc_start_host->_mmc_detect_change -> mmc_rescan ->mmc_rescan_try_freq,对于REMOVALBE设备,rescan可以进行多次,而对于mmc这样的NON-REMOVABLE设备,只需扫描一次即可。
host会使用不同的频率发送命令到device,因此这个函数也是尝试设置f_init的过程
mmc_power_up Power_up流程,可参见MMC spec5.0 A6.1,首先设置总线操作电压,然后设置clock
mmc_attach_mmc: mmc 卡初始化函数
mmc_send_op_cond等待device完成power up过程
mmc_select_voltage检查前面获得的ocr,判断ocr中标称的电压,返回的ocr为处理过的ocr
mmc_init_card 会读取cid csd ext_csd,并根据这些寄存器的值做一些初始化操作。
158 如果发现ocr的最高位为1,表示mmc device已经完成power up,否则循环发送CMD1,直到mmc device 完成power up
1016 mmc_all_send_cid 发送CMD10,并等待device 返回R2。CMD10请求设备发送CID给host
1088 获取ext_csd,ext_csd的获取,需要发送MMC_SEND_EXT_CSD,并从data线上获取device发送回ext_csd
1091 解析获取的ext_csd
那么理论上总线应该能跑到HS200,此时就设置ext_csd.hs_max_dtr为MMC_HS200_MAX_DTR
mmc_select_hs200设置device的timing为HS200
mmc_set_timing则设置host的timing 为HS200
设置host的最大clock
但是低耗电带来的副作用就是性能的损失,所以linux emmc core 驱动都是性能优先。
mmc_add_card
352~370会输出mmc card的一些信息,比如high speed, HS200;DDR等
379会调用设备模型,增加设备,因为card属于mmc_bus,会调用mmc_bus_probe
这样理解,每个mmc设备也是一个block设备,因此这个mmc设备,也要对应一个mmc block驱动。mmc block驱动需要调用驱动本身的probe函数,探测这个block设备
2440 每一个mmc_card都对应一个mmc_blk_data,mmc_blk_data管理快设备相关的数据。
2450 mmc设备内部可能预先分配了boot partitions,以及最多四个general purpose partitions,需要为这些内置分区分配part。注意这些分区在系统中是以通用磁盘的形式存在的,并不是传统意义上的分区。
2456 mmc_add_disk增加mmc 设备到系统中,mmc_add_disk会调用add_disk向系统内增加通用硬盘,这个函数比较复杂,会单独开一个帖子分析add_disk的流程。
mmc_add_disk结束后,mmc设备的分区信息也已经添加到系统中。
mmc_blk_data主要实现函数是mmc_blk_alloc_req
2116 alloc_disk分配一个gendisk结构,在linux内核中gendisk用来表示一个磁盘或者分区
2126 初始化该块设备的queue,从这里我们可以看出不管mmc_blk_data对应是磁盘还是分区,都会为它分配queue。这是合理的,比如我们可以通过/dev/mmcblk0访问设备,也可以通过/dev/mmcblk0p1访问设备。
用的是TI 平台,仅分析MMC,不分析SD和SDIO
mmc_init
2769 static int __init mmc_init(void) 2770 { 2774 2775 workqueue = alloc_ordered_workqueue("kmmcd", 0); 2776 if (!workqueue) 2777 return -ENOMEM; 2778 2779 ret = mmc_register_bus(); 2780 if (ret) 2781 goto destroy_workqueue; 2782 2783 ret = mmc_register_host_class(); 2784 if (ret) 2785 goto unregister_bus;; 2793 2802 }
2775分配一个workqueue,这个workqueue是专门用来处理card detect的,EMMC因为是unremovable的,所以不需要关注它
2779 注册mmc_bus_type,实现如下:
int mmc_register_bus(void) { return bus_register(&mmc_bus_type); }把mmc_bus_type注册到bus系统,后面调用device_add函数时,则会辗转调用到mmc_bus_type中的probe函数,不必太纠结在这个代码
mmc_init调用时间比较早,会在host驱动初始化之前执行完。
subsys_initcall(mmc_init);
host驱动初始化
kernel/drivers/mmc/host/omap_hsmmc.chost驱动位置是kernel/drivers/mmc/host/,一般来说都是platform_driver,以omap hsmmc host驱动为例
<strong>.probe = omap_hsmmc_probe,</strong> .remove = omap_hsmmc_remove, .driver = { .name = DRIVER_NAME, .owner = THIS_MODULE, .pm = &omap_hsmmc_dev_pm_ops, .of_match_table = of_match_ptr(omap_mmc_of_match), }, }; module_platform_driver(omap_hsmmc_driver);
只需要关注omap_hsmmc_probe即可,当系统匹配到platform_device时,会调用omap_hsmmc_probe,好长的一个函数
2627 base = devm_ioremap_resource(&pdev->dev, res); 2628 if (IS_ERR(base)) 2629 return PTR_ERR(base); 2630 2631 ret = omap_hsmmc_gpio_init(pdata); 2632 if (ret) 2633 goto err;devm_ioremap_resource,实质就是ioremap,设备特定io资源到内核地址的映射,自行脑补一下ioremap。
omap_hsmmc_gpio_init是card detect和write protect gpio的初始化,Ignore it!!!
2635 mmc = mmc_alloc_host(sizeof(struct omap_hsmmc_host), &pdev->dev); 2636 if (!mmc) { 2637 ret = -ENOMEM; 2638 goto err_alloc; 2639 } ...............mmc_alloc_host,分配一个omap_hsmmc_host结构(包含struct mmc_host),以供后面玩耍
2661 mmc->ops = &omap_hsmmc_ops; 2410 static const struct mmc_host_ops omap_hsmmc_ops = { 2411 .enable = omap_hsmmc_enable_fclk, 2412 .disable = omap_hsmmc_disable_fclk, 2413 .post_req = omap_hsmmc_post_req, 2414 .pre_req = omap_hsmmc_pre_req, 2415 .request = omap_hsmmc_request, 2416 .set_ios = omap_hsmmc_set_ios, 2417 .get_cd = omap_hsmmc_get_cd, 2418 .get_ro = omap_hsmmc_get_ro, 2419 .init_card = omap_hsmmc_init_card, 2420 .start_signal_voltage_switch = omap_start_signal_voltage_switch, 2421 .card_busy = omap_hsmmc_card_busy, 2422 .execute_tuning = omap_execute_tuning, 2423 /* NYET -- enable_sdio_irq */ 2424 };omap hsmmc host驱动和mmc子系统的所有接口都在这里了。
2663 mmc->f_min = OMAP_MMC_MIN_CLOCK; 2675 if (pdata->max_freq > 0) { 2676 mmc->f_max = pdata->max_freq; 2677 ret = clk_set_rate(host->fclk, pdata->max_freq); 2678 if (ret) { 2679 dev_err(dev, "failed to set clock to %d\n", 2680 pdata->max_freq); 2681 goto err1; 2682 } 2683 } else { 2684 mmc->f_max = OMAP_MMC_MAX_CLOCK; 2685 }定义了最小时钟400K,在系统初始化阶段为了兼容的原因会使用这个时钟。最大时钟为52MHZ,后面还有机会再修改这个时钟频率。
2724 mmc->max_segs = 1024; 2725 2726 mmc->max_blk_size = 512; /* Block Length at max can be 1024 */ 2727 mmc->max_blk_count = 0xFFFF; /* No. of Blocks is 16 bits */ 2728 mmc->max_req_size = mmc->max_blk_size * mmc->max_blk_count; 2729 mmc->max_seg_size = mmc->max_req_size;
mmc作为快设备,最主要的操作就是数据sectors读写,max_segs定义了block设备的request所支持的最大segment
max_blk_count 一个request中所包含的最大block数
其实多少都不重要,反正就是和request相关的一些上限。
2731 mmc->caps |= MMC_CAP_MMC_HIGHSPEED | MMC_CAP_SD_HIGHSPEED | 2732 MMC_CAP_WAIT_WHILE_BUSY | MMC_CAP_ERASE; 2733 2734 mmc->caps |= mmc_slot(host).caps; 2735 if (mmc->caps & MMC_CAP_8_BIT_DATA) 2736 mmc->caps |= MMC_CAP_4_BIT_DATA; 2737 if (mmc_slot(host).nonremovable) 2738 mmc->caps |= MMC_CAP_NONREMOVABLE; 2741 2742 if (of_property_read_bool(np, "sd-uhs-sdr12")) 2743 mmc->caps |= MMC_CAP_UHS_SDR12; 2744 if (of_property_read_bool(np, "sd-uhs-sdr25")) 2745 mmc->caps |= MMC_CAP_UHS_SDR25; 2746 if (of_property_read_bool(np, "sd-uhs-sdr50")) 2747 mmc->caps |= MMC_CAP_UHS_SDR50; 2748 if (of_property_read_bool(np, "sd-uhs-sdr104")) 2749 mmc->caps |= MMC_CAP_UHS_SDR104; 2750 if (of_property_read_bool(np, "sd-uhs-ddr50")) 2751 mmc->caps |= MMC_CAP_UHS_DDR50; 2752 if (of_property_read_bool(np, "mmc-ddr-1_8v")) 2753 mmc->caps |= MMC_CAP_1_8V_DDR; 2754 if (of_property_read_bool(np, "mmc-hs200-1_8v")) 2755 mmc->caps2 |= MMC_CAP2_HS200_1_8V_SDR;mmc->caps 表示host能力的标志,mmc->caps2 表示host更多的能力,也许有一天会添加mmc->caps3这个字段
MMCCAP_MMC_HIGHSPEED, MMC_CAP_SD_HIGHSPEED MMC_CAP_WAIT_WHILE_BUSY MMC_CAP_ERASE是最基本的能力
MMC_CAP_8_BIT_DATA表示数据总线是多少,EMMC 数据线支持8线,4线和1线。
2742 ~ 2755 通过of系统定义的一些特定能力,当前MMC_CAP_1_8V_DDR,MMC_CAP2_HS200_1_8V_SDR都很常见了。DDR是Double Date Rate的缩写,SDR是Single Data Rate的缩写
自行脑补百度资料DDR SDRAM, EMMC的DDR SDR与之类似。
DDR=Double Data Rate双倍速率同步动态随机存储器。严格的说DDR应该叫DDR SDRAM,人们习惯称为DDR,其中,SDRAM 是Synchronous Dynamic Random Access Memory的缩写,
即同步动态随机存取存储器。而DDR SDRAM是Double Data Rate SDRAM的缩写,是双倍速率同步动态随机存储器的意思。DDR内存是在SDRAM内存基础上发展而来的,仍然沿用SDRAM生产体系,
一个时钟周期内进行两次读/写操作,即在时钟的上升沿和下降沿分别执行一次读/写操作。
因此对于内存厂商而言,只需对制造普通SDRAM的设备稍加改进,即可实现DDR内存的生产,可有效的降低成本。Double Data Rate:与传统的单数据速率相比,DDR技术实现了一个时钟周期内进行两次读/写操作,即在时钟的上升沿和下降沿分别执行一次读/写操作。
注意对于EMMC CMD线来说,是没有DDR SDR说法的,CMD和response只在clock的上升沿传输,参见EMMC spec5.0 section 6.15.1
2773 omap_hsmmc_conf_bus_power(host);设置EMMC总线电压,EMMC芯片支持3.3V, 1.8V和1.2V总线信号电压,host需要和EMMC芯片的电压匹配(就是相同了)。
2775 if (!pdev->dev.of_node) { 2776 res = platform_get_resource_byname(pdev, IORESOURCE_DMA, "tx"); 2777 if (!res) { 2778 dev_err(mmc_dev(host->mmc), "cannot get DMA TX channel\n"); 2779 ret = -ENXIO; 2780 goto err_irq; 2781 } 2782 tx_req = res->start; 2783 2784 res = platform_get_resource_byname(pdev, IORESOURCE_DMA, "rx"); 2785 if (!res) { 2786 dev_err(mmc_dev(host->mmc), "cannot get DMA RX channel\n"); 2787 ret = -ENXIO; 2788 goto err_irq; 2789 } 2790 rx_req = res->start; 2791 } 2792 2793 dma_cap_zero(mask); 2794 dma_cap_set(DMA_SLAVE, mask); 2795 2796 host->rx_chan = 2797 dma_request_slave_channel_compat(mask, omap_dma_filter_fn, 2798 &rx_req, &pdev->dev, "rx"); 2799 2800 if (!host->rx_chan) { 2801 dev_err(mmc_dev(host->mmc), "unable to obtain RX DMA engine channel %u\n", rx_req); 2802 ret = -ENXIO; 2803 goto err_irq; 2804 } 2805 2806 host->tx_chan = 2807 dma_request_slave_channel_compat(mask, omap_dma_filter_fn, 2808 &tx_req, &pdev->dev, "tx");
DMA相关的代码,内核中EMMC驱动必然要使用DMA方式读写数据,
dma_request_slave_channel_compat分配一个DMA channel
2816 /* Request IRQ for MMC operations */ 2817 ret = devm_request_irq(&pdev->dev, host->irq, omap_hsmmc_irq, 0, 2818 mmc_hostname(mmc), host); 2819 if (ret) { 2820 dev_err(mmc_dev(host->mmc), "Unable to grab HSMMC IRQ\n"); 2821 goto err_irq; 2822 }设置中断处理函数,omap_hsmmc_irq负责处理EMMC 命令和EMMC DMA数据传输。
2864 mmc_add_host(mmc); drivers/mmc/core/host.c 538 int mmc_add_host(struct mmc_host *host) 539 { 557 mmc_start_host(host); 562 }初始换mmc host硬件,mmc_start_host会负责扫描mmc设备
mmc_start_host->_mmc_detect_change -> mmc_rescan ->mmc_rescan_try_freq,对于REMOVALBE设备,rescan可以进行多次,而对于mmc这样的NON-REMOVABLE设备,只需扫描一次即可。
host会使用不同的频率发送命令到device,因此这个函数也是尝试设置f_init的过程
2362 static int mmc_rescan_try_freq(struct mmc_host *host, unsigned freq) 2363 { 2364 host->f_init = freq; 2365 2371 mmc_power_up(host, host->ocr_avail); 2372 2389 /* Order's important: probe SDIO, then SD, then MMC */ 2390 if (!mmc_attach_sdio(host)) 2391 return 0; 2392 if (!mmc_attach_sd(host)) 2393 return 0; 2394 if (!mmc_attach_mmc(host)) { 2395 printk(KERN_ERR "%s: end, host->index=%d\n", __func__, host->index); 2396 return 0; 2397 } 2401 }分别用400K 300K 200K 100K 频率尝试和device通信,不过400K就会成功
mmc_power_up Power_up流程,可参见MMC spec5.0 A6.1,首先设置总线操作电压,然后设置clock
mmc_attach_mmc: mmc 卡初始化函数
1785 int mmc_attach_mmc(struct mmc_host *host) 1786 { 1792 1794 /* Set correct bus mode for MMC before attempting attach */ 1795 if (!mmc_host_is_spi(host)) 1796 mmc_set_bus_mode(host, MMC_BUSMODE_OPENDRAIN); 1797 1798 err = mmc_send_op_cond(host, 0, &ocr); 1799 if (err) 1800 return err; 1804 1805 mmc_attach_bus_ops(host); 1806 if (host->ocr_avail_mmc) 1807 host->ocr_avail = host->ocr_avail_mmc; 1808 1817 1818 rocr = mmc_select_voltage(host, ocr); 1819 1827 1828 /* 1829 * Detect and init the card. 1830 */ 1831 err = mmc_init_card(host, rocr, NULL); 1832 if (err) 1833 goto err; 1834 1835 mmc_release_host(host); 1836 err = mmc_add_card(host->card); 1837 mmc_claim_host(host); 1838 if (err) 1839 goto remove_card; 1840 1842 return 0; 1856 }
mmc_send_op_cond等待device完成power up过程
mmc_select_voltage检查前面获得的ocr,判断ocr中标称的电压,返回的ocr为处理过的ocr
mmc_init_card 会读取cid csd ext_csd,并根据这些寄存器的值做一些初始化操作。
133 int mmc_send_op_cond(struct mmc_host *host, u32 ocr, u32 *rocr) 134 { 135 struct mmc_command cmd = {0}; 136 int i, err = 0; 139 140 cmd.opcode = MMC_SEND_OP_COND; 141 cmd.arg = mmc_host_is_spi(host) ? 0 : ocr; 142 cmd.flags = MMC_RSP_SPI_R1 | MMC_RSP_R3 | MMC_CMD_BCR; 143 144 for (i = 100; i; i--) { 145 err = mmc_wait_for_cmd(host, &cmd, 0); 146 if (err) 147 break; 148 149 /* if we're just probing, do a single pass */ 150 if (ocr == 0) 151 break; 152 153 /* otherwise wait until reset completes */ 154 if (mmc_host_is_spi(host)) { 155 if (!(cmd.resp[0] & R1_SPI_IDLE)) 156 break; 157 } else { 158 if (cmd.resp[0] & MMC_CARD_BUSY) 159 break; 160 } 161 162 err = -ETIMEDOUT; 163 164 mmc_delay(10); 165 } 166 167 if (rocr && !mmc_host_is_spi(host)) 168 *rocr = cmd.resp[0]; 169 170 return err; 171 }145 发送CMD1并等待R3
158 如果发现ocr的最高位为1,表示mmc device已经完成power up,否则循环发送CMD1,直到mmc device 完成power up
969 static int mmc_init_card(struct mmc_host *host, u32 ocr, 970 struct mmc_card *oldcard) 971 { 995 996 /* The extra bit indicates that we support high capacity */ 997 err = mmc_send_op_cond(host, ocr | (1 << 30), &rocr); 998 if (err) 999 goto err; 1000 1010 /* 1011 * Fetch CID from card. 1012 */ 1013 if (mmc_host_is_spi(host)) 1014 err = mmc_send_cid(host, cid); 1015 else 1016 err = mmc_all_send_cid(host, cid); 1017 if (err) 1018 goto err;997 ocr | (1 << 30) 表示驱动支持的是sector模式,Linux EMMC 子系统强制使用sector模式。
1016 mmc_all_send_cid 发送CMD10,并等待device 返回R2。CMD10请求设备发送CID给host
1047 /* 1048 * For native busses: set card RCA and quit open drain mode. 1049 */ 1050 if (!mmc_host_is_spi(host)) { 1051 err = mmc_set_relative_addr(card); 1052 if (err) 1053 goto free_card; 1054 1055 mmc_set_bus_mode(host, MMC_BUSMODE_PUSHPULL); 1056 }对于本地总线,也就是相对于spi emmc总线,需要设置emmc chip地址,并且设置总线模式为PUSHPULL
1058 if (!oldcard) { 1059 /* 1060 * Fetch CSD from card. 1061 */ 1062 err = mmc_send_csd(card, card->raw_csd); 1063 if (err) 1064 goto free_card; 1065 1066 err = mmc_decode_csd(card); 1067 if (err) 1068 goto free_card; 1069 err = mmc_decode_cid(card); 1070 if (err) 1071 goto free_card; 1072 }1062 发送MMC_SEND_CSD CMD9获取设备csd寄存器
1077 if (!mmc_host_is_spi(host)) { 1078 err = mmc_select_card(card); 1079 if (err) 1080 goto free_card; 1081 }1078 发送MMC_SELECT_CARD CMD7选择设备,device的状态会从standby状态转化为transfer状态。
1083 if (!oldcard) { 1084 /* 1085 * Fetch and process extended CSD. 1086 */ 1087 1088 err = mmc_get_ext_csd(card, &ext_csd); 1089 if (err) 1090 goto free_card; 1091 err = mmc_read_ext_csd(card, ext_csd); 1092 if (err) 1093 goto free_card; 1094 1095 /* If doing byte addressing, check if required to do sector 1096 * addressing. Handle the case of <2GB cards needing sector 1097 * addressing. See section 8.1 JEDEC Standard JED84-A441; 1098 * ocr register has bit 30 set for sector addressing. 1099 */ 1100 if (!(mmc_card_blockaddr(card)) && (rocr & (1<<30))) 1101 mmc_card_set_blockaddr(card); 1102 1103 /* Erase size depends on CSD and Extended CSD */ 1104 mmc_set_erase_size(card); 1105 }
1088 获取ext_csd,ext_csd的获取,需要发送MMC_SEND_EXT_CSD,并从data线上获取device发送回ext_csd
1091 解析获取的ext_csd
1174 if (card->ext_csd.hs_max_dtr != 0) { 1175 err = 0; 1176 if (card->ext_csd.hs_max_dtr > 52000000 && 1177 host->caps2 & MMC_CAP2_HS200) 1178 err = mmc_select_hs200(card); 1179 else if (host->caps & MMC_CAP_MMC_HIGHSPEED) 1180 err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL, 1181 EXT_CSD_HS_TIMING, 1, 1182 card->ext_csd.generic_cmd6_time); 1183 1184 if (err && err != -EBADMSG) 1185 goto free_card; 1186 1187 if (err) { 1188 pr_warning("%s: switch to highspeed failed\n", 1189 mmc_hostname(card->host)); 1190 err = 0; 1191 } else { 1192 if (card->ext_csd.hs_max_dtr > 52000000 && 1193 host->caps2 & MMC_CAP2_HS200) { 1194 mmc_card_set_hs200(card); 1195 mmc_set_timing(card->host, 1196 MMC_TIMING_MMC_HS200); 1198 } else { 1199 mmc_card_set_highspeed(card); 1200 mmc_set_timing(card->host, MMC_TIMING_MMC_HS); 1202 } 1203 } 1204 }ext_csd.hs_max_dtr已经在mmc_select_card_type中设置为可支持的最大速度,这个值是由ext_csd[CARD_TYPE]以及host-caps2来决定的。比如host支持HS200,device 也支持HS200
那么理论上总线应该能跑到HS200,此时就设置ext_csd.hs_max_dtr为MMC_HS200_MAX_DTR
mmc_select_hs200设置device的timing为HS200
mmc_set_timing则设置host的timing 为HS200
1211 if (mmc_card_highspeed(card) || mmc_card_hs200(card)) { 1212 if (max_dtr > card->ext_csd.hs_max_dtr) 1213 max_dtr = card->ext_csd.hs_max_dtr; 1214 if (mmc_card_highspeed(card) && (max_dtr > 52000000)) 1215 max_dtr = 52000000; 1216 } else if (max_dtr > card->csd.max_dtr) { 1217 max_dtr = card->csd.max_dtr; 1218 } 1219 1220 printk(KERN_ERR "%s: mmc_set_clock() max_dtr=%d\n", __func__, max_dtr); 1221 mmc_set_clock(host, max_dtr);
设置host的最大clock
1267 ext_csd_bits = (bus_width == MMC_BUS_WIDTH_8) ? 1268 EXT_CSD_BUS_WIDTH_8 : EXT_CSD_BUS_WIDTH_4; 1269 err = mmc_select_powerclass(card, ext_csd_bits);1269 设置device 的power class。关于power class, EMMC spec为了让host端控制EMMC芯片的耗电范围,允许host设置ext_csd的POWER_CLASS[187]来控制device的耗电行为。
但是低耗电带来的副作用就是性能的损失,所以linux emmc core 驱动都是性能优先。
mmc_add_card
309 int mmc_add_card(struct mmc_card *card) 310 { 351 352 if (mmc_card_uhs(card) && 353 (card->sd_bus_speed < ARRAY_SIZE(uhs_speeds))) 354 uhs_bus_speed_mode = uhs_speeds[card->sd_bus_speed]; 355 356 if (mmc_host_is_spi(card->host)) { 357 pr_info("%s: new %s%s%s card on SPI\n", 358 mmc_hostname(card->host), 359 mmc_card_highspeed(card) ? "high speed " : "", 360 mmc_card_ddr_mode(card) ? "DDR " : "", 361 type); 362 } else { 363 pr_info("%s: new %s%s%s%s%s card at address %04x\n", 364 mmc_hostname(card->host), 365 mmc_card_uhs(card) ? "ultra high speed " : 366 (mmc_card_highspeed(card) ? "high speed " : ""), 367 (mmc_card_hs200(card) ? "HS200 " : ""), 368 mmc_card_ddr_mode(card) ? "DDR " : "", 369 uhs_bus_speed_mode, type, card->rca); 370 } 379 ret = device_add(&card->dev);
352~370会输出mmc card的一些信息,比如high speed, HS200;DDR等
379会调用设备模型,增加设备,因为card属于mmc_bus,会调用mmc_bus_probe
110 static int mmc_bus_probe(struct device *dev) 111 { 112 int ret; 113 struct mmc_driver *drv = to_mmc_driver(dev->driver); 114 struct mmc_card *card = mmc_dev_to_card(dev); 115 117 ret = drv->probe(card); 118 120 return ret; 121 }drv->probe对应的是mmc/card/block.c中的mmc_driver-.probe
这样理解,每个mmc设备也是一个block设备,因此这个mmc设备,也要对应一个mmc block驱动。mmc block驱动需要调用驱动本身的probe函数,探测这个block设备
2429 static int mmc_blk_probe(struct mmc_card *card) 2430 { 2431 struct mmc_blk_data *md, *part_md; 2432 char cap_str[10]; 2439 2440 md = mmc_blk_alloc(card); 2441 if (IS_ERR(md)) 2442 return PTR_ERR(md); 2443 2444 string_get_size((u64)get_capacity(md->disk) << 9, STRING_UNITS_2, 2445 cap_str, sizeof(cap_str)); 2446 pr_info("%s: %s %s %s %s\n", 2447 md->disk->disk_name, mmc_card_id(card), mmc_card_name(card), 2448 cap_str, md->read_only ? "(ro)" : ""); 2449 2450 if (mmc_blk_alloc_parts(card, md)) 2451 goto out; 2452 2453 mmc_set_drvdata(card, md); 2454 mmc_fixup_device(card, blk_fixups); 2455 2456 if (mmc_add_disk(md)) 2457 goto out; 2458 2459 list_for_each_entry(part_md, &md->part, part) { 2460 if (mmc_add_disk(part_md)) 2461 goto out; 2462 } 2467 /* 2468 * Don't enable runtime PM for SD-combo cards here. Leave that 2469 * decision to be taken during the SDIO init sequence instead. 2470 */ 2471 if (card->type != MMC_TYPE_SD_COMBO) { 2472 pm_runtime_set_active(&card->dev); 2473 pm_runtime_enable(&card->dev); 2474 } 2475 2476 return 0; 2477 2478 out: 2479 mmc_blk_remove_parts(card, md); 2480 mmc_blk_remove_req(md); 2481 return 0; 2482 }
2440 每一个mmc_card都对应一个mmc_blk_data,mmc_blk_data管理快设备相关的数据。
2450 mmc设备内部可能预先分配了boot partitions,以及最多四个general purpose partitions,需要为这些内置分区分配part。注意这些分区在系统中是以通用磁盘的形式存在的,并不是传统意义上的分区。
2456 mmc_add_disk增加mmc 设备到系统中,mmc_add_disk会调用add_disk向系统内增加通用硬盘,这个函数比较复杂,会单独开一个帖子分析add_disk的流程。
mmc_add_disk结束后,mmc设备的分区信息也已经添加到系统中。
mmc_blk_data主要实现函数是mmc_blk_alloc_req
2074 static struct mmc_blk_data *mmc_blk_alloc_req(struct mmc_card *card, 2075 struct device *parent, 2076 sector_t size, 2077 bool default_ro, 2078 const char *subname, 2079 int area_type) 2080 { 2116 md->disk = alloc_disk(perdev_minors); 2117 if (md->disk == NULL) { 2118 ret = -ENOMEM; 2119 goto err_kfree; 2120 } 2126 ret = mmc_init_queue(&md->queue, card, &md->lock, subname); 2127 if (ret) 2128 goto err_putdisk;
2116 alloc_disk分配一个gendisk结构,在linux内核中gendisk用来表示一个磁盘或者分区
2126 初始化该块设备的queue,从这里我们可以看出不管mmc_blk_data对应是磁盘还是分区,都会为它分配queue。这是合理的,比如我们可以通过/dev/mmcblk0访问设备,也可以通过/dev/mmcblk0p1访问设备。
相关文章推荐
- linux的mmc_spi学习笔记
- eMMC的MMC模式与SPI模式
- MMC卡原理和操作分析
- 基于OMAP的MPEG—4实时解码器的实现
- BeagleBoneBlack(Chipsee)更新emmc
- eMMC技术教程(一): eMMC是什么?可以做到多大容量(转自youdianhai.com)
- EMMC的发展
- ARM+DSP双核处理器应用程序攻略
- Davinci OMap开发资料 集锦
- DAVINCI和OMAP架构的区别
- 利用mmc_test.c研究mmc模块
- EMMC 发展
- DRAM、SDRAM 和 SRAM的 区别
- 友善之臂tiny4412使用DNW将uboot烧录到emmc
- omap5 eMMC 启动流程
- Gstreamer开发
- [emmc] emmc总线设置
- 手动替换A20 镜像中的文件
- SD卡、TF卡、MMC卡以及eMMC芯片的介绍
- Nor Flash、Nand Flash和eMMC的区别