emmc host调用mmc_rescan发现设备

本文解析了MMC启动过程中涉及的关键步骤,包括mmc_start_host函数的工作原理、mmc_rescan_try_freq函数如何尝试不同频率初始化设备,以及mmc_attach_sdio等函数如何探测和配置SDIO、SD和MMC设备。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

在调用mmc_start_host 来enable一个emmc host的时候
void mmc_start_host(struct mmc_host *host)
{
    host->f_init = max(freqs[0], host->f_min);
    host->rescan_disable = 0;
    host->ios.power_mode = MMC_POWER_UNDEFINED;

    mmc_claim_host(host);
    if (host->caps2 & MMC_CAP2_NO_PRESCAN_POWERUP)
        mmc_power_off(host);
    else
        mmc_power_up(host, host->ocr_avail);
    mmc_release_host(host);

    mmc_gpiod_request_cd_irq(host);
    _mmc_detect_change(host, 0, false);
}
在mmc_start_host 通过_mmc_detect_change 来启动scan连接在这个host上的mmc device
static void _mmc_detect_change(struct mmc_host *host, unsigned long delay,
                bool cd_irq)
{
    /*
     * If the device is configured as wakeup, we prevent a new sleep for
     * 5 s to give provision for user space to consume the event.
     */
    if (cd_irq && !(host->caps & MMC_CAP_NEEDS_POLL) &&
        device_can_wakeup(mmc_dev(host)))
        pm_wakeup_event(mmc_dev(host), 5000);

    host->detect_change = 1;
    mmc_schedule_delayed_work(&host->detect, delay);
}
置位host->detect_change,并调用mmc_schedule_delayed_work 来scan device
static int mmc_schedule_delayed_work(struct delayed_work *work,
                     unsigned long delay)
{
    return queue_delayed_work(system_freezable_wq, work, delay);
}
但是这个host->detect这个work对应的func 是通过下面的方式赋值
而在mmc_alloc_host 中的赋值如下:
    INIT_DELAYED_WORK(&host->detect, mmc_rescan);
这样当调用mmc_schedule_delayed_work的时候,会调用mmc_rescan
在mmc_rescan 中最要的如下:
    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;
    }

static const unsigned freqs[] = { 400000, 300000, 200000, 100000 };
可以看到每个host 最多scan四次,在当前freqs上找到device就退出
static int mmc_rescan_try_freq(struct mmc_host *host, unsigned freq)
{
    host->f_init = freq;

#ifdef CONFIG_MMC_DEBUG
    pr_info("%s: %s: trying to init card at %u Hz\n",
        mmc_hostname(host), __func__, host->f_init);
#endif
    mmc_power_up(host, host->ocr_avail);

    /*
     * Some eMMCs (with VCCQ always on) may not be reset after power up, so
     * do a hardware reset if possible.
     */
    mmc_hw_reset_for_init(host);

    /*
     * sdio_reset sends CMD52 to reset card.  Since we do not know
     * if the card is being re-initialized, just send it.  CMD52
     * should be ignored by SD/eMMC cards.
     * Skip it if we already know that we do not support SDIO commands
     */
    if (!(host->caps2 & MMC_CAP2_NO_SDIO))
        sdio_reset(host);

    mmc_go_idle(host);

    if (!(host->caps2 & MMC_CAP2_NO_SD))
        mmc_send_if_cond(host, host->ocr_avail);

    /* Order's important: probe SDIO, then SD, then MMC */
    if (!(host->caps2 & MMC_CAP2_NO_SDIO))
        if (!mmc_attach_sdio(host))
            return 0;

    if (!(host->caps2 & MMC_CAP2_NO_SD))
        if (!mmc_attach_sd(host))
            return 0;

    if (!(host->caps2 & MMC_CAP2_NO_MMC))
        if (!mmc_attach_mmc(host))
            return 0;

    mmc_power_off(host);
    return -EIO;
}

可以从mmc_rescan_try_freq看到,emmc host上可以挂三种设备,这三种设别只能挂一个不能共存,且有一定的优先级
其中优先级为:mmc->sd->sdio
以mmc_attach_sdio->mmc_add_card为例开机会打印如下log
[   11.565233] mmc_host mmc2: Bus speed (slot 0) = 25000000Hz (slot req 2500000)
++ Setting up mdev                                                              
[   11.587289] mmc2: queuing unknown CIS tuple 0x91 (3 bytes)                   
[   11.599206] mmc2: new SDIO card at address 0001     

在mmc_rescan_try_freq 中是通过host->caps2 & MMC_CAP2_NO_SDIO 来判断是否有SDIO的,也就是如果在mmc_of_parse中没有添加这个flag就默认调用mmc_attach_sdio。而mmc_of_parse 是在parse host对应的dts,也就是说在dts中如果没有
    if (of_property_read_bool(np, "no-sdio"))
        host->caps2 |= MMC_CAP2_NO_SDIO;
就默认调用mmc_attach_sdio

int mmc_of_parse(struct mmc_host *host)
{
    
    if (of_property_read_bool(np, "disable-wp"))
        host->caps2 |= MMC_CAP2_NO_WRITE_PROTECT;

    /* See the comment on CD inversion above */
    if (ro_cap_invert ^ ro_gpio_invert)
        host->caps2 |= MMC_CAP2_RO_ACTIVE_HIGH;

    if (of_property_read_bool(np, "cap-sd-highspeed"))
        host->caps |= MMC_CAP_SD_HIGHSPEED;
    if (of_property_read_bool(np, "cap-mmc-highspeed"))
        host->caps |= MMC_CAP_MMC_HIGHSPEED;
    if (of_property_read_bool(np, "sd-uhs-sdr12"))
        host->caps |= MMC_CAP_UHS_SDR12;
    if (of_property_read_bool(np, "sd-uhs-sdr25"))
        host->caps |= MMC_CAP_UHS_SDR25;
    if (of_property_read_bool(np, "sd-uhs-sdr50"))
        host->caps |= MMC_CAP_UHS_SDR50;
    if (of_property_read_bool(np, "sd-uhs-sdr104"))
        host->caps |= MMC_CAP_UHS_SDR104;
    if (of_property_read_bool(np, "sd-uhs-ddr50"))
        host->caps |= MMC_CAP_UHS_DDR50;
    if (of_property_read_bool(np, "cap-power-off-card"))
        host->caps |= MMC_CAP_POWER_OFF_CARD;
    if (of_property_read_bool(np, "cap-mmc-hw-reset"))
        host->caps |= MMC_CAP_HW_RESET;
    if (of_property_read_bool(np, "cap-sdio-irq"))
        host->caps |= MMC_CAP_SDIO_IRQ;
    if (of_property_read_bool(np, "full-pwr-cycle"))
        host->caps2 |= MMC_CAP2_FULL_PWR_CYCLE;
    if (of_property_read_bool(np, "keep-power-in-suspend"))
        host->pm_caps |= MMC_PM_KEEP_POWER;
    
}
void mmc_rescan(struct work_struct *work) 2214 { 2215 struct mmc_host *host = 2216 container_of(work, struct mmc_host, detect.work); 2217 int i; 2218 2219 if (host->rescan_disable) 2220 return; 2221 2222 /* If there is a non-removable card registered, only scan once */ 2223 if (!mmc_card_is_removable(host) && host->rescan_entered) 2224 return; 2225 host->rescan_entered = 1; 2226 2227 if (host->trigger_card_event && host->ops->card_event) { 2228 mmc_claim_host(host); 2229 host->ops->card_event(host); 2230 mmc_release_host(host); 2231 host->trigger_card_event = false; 2232 } 2233 2234 /* Verify a registered card to be functional, else remove it. */ 2235 if (host->bus_ops) 2236 host->bus_ops->detect(host); 2237 2238 host->detect_change = 0; 2239 2240 /* if there still is a card present, stop here */ 2241 if (host->bus_ops != NULL) 2242 goto out; 2243 2244 mmc_claim_host(host); 2245 if (mmc_card_is_removable(host) && host->ops->get_cd && 2246 host->ops->get_cd(host) == 0) { 2247 mmc_power_off(host); 2248 mmc_release_host(host); 2249 goto out; 2250 } 2251 2252 /* If an SD express card is present, then leave it as is. */ 2253 if (mmc_card_sd_express(host)) { 2254 mmc_release_host(host); 2255 goto out; 2256 } 2257 2258 for (i = 0; i < ARRAY_SIZE(freqs); i++) { 2259 unsigned int freq = freqs[i]; 2260 if (freq > host->f_max) { 2261 if (i + 1 < ARRAY_SIZE(freqs)) 2262 continue; 2263 freq = host->f_max; 2264 } 2265 if (!mmc_rescan_try_freq(host, max(freq, host->f_min))) 2266 break; 2267 if (freqs[i] <= host->f_min) 2268 break; 2269 } 2270 2271 /* A non-removable card should have been detected by now. */ 2272 if (!mmc_card_is_removable(host) && !host->bus_ops) 2273 pr_info("%s: Failed to initialize a non-removable card", 2274 mmc_hostname(host)); 2275 2276 /* 2277 * Ignore the command timeout errors observed during 2278 * the card init as those are excepted. 2279 */ 2280 host->err_stats[MMC_ERR_CMD_TIMEOUT] = 0; 2281 mmc_release_host(host); 2282 2283 out: 2284 if (host->caps & MMC_CAP_NEEDS_POLL) 2285 mmc_schedule_delayed_work(&host->detect, HZ); 2286 }
最新发布
07-23
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值