/* * Mask off any voltages we don't support and select * the lowest voltage */ u32 mmc_select_voltage(struct mmc_host *host, u32 ocr)
电压test and select后,进入探测初始化mmc_sdio_init_card(host, rocr, NULL):
/* * Handle the detection and initialisation of a card. * * In the case of a resume, "oldcard" will contain the card * we're trying to reinitialise. */ staticintmmc_sdio_init_card(struct mmc_host *host, u32 ocr, struct mmc_card *oldcard) {
/* * For native busses: set card RCA and quit open drain mode. */ if (!mmc_host_is_spi(host)) { err = mmc_send_relative_addr(host, &card->rca); if (err) goto remove;
err = mmc_wait_for_cmd(host, &cmd, MMC_CMD_RETRIES); if (err) return err;
*rca = cmd.resp[0] >> 16; //tj: get RCA
return0; }
then select card(due to 操作依赖):
/* * Select card, as all following commands rely on that. */ if (!mmc_host_is_spi(host)) { err = mmc_select_card(card); if (err) goto remove; }
then 读common information area(CIA),包括CCCR(card common control)和CIS(card information struture):
/* * Read the common registers. Note that we should try to * validate whether UHS would work or not. */ err = sdio_read_cccr(card, ocr); ... /* * Read the common CIS tuples. */ err = sdio_read_common_cis(card);
目的就是让host决定要用哪些功能,最后设置High-Speed if support/clock/4-bit SD if support:
/* * Change to the card's maximum speed. */ mmc_set_clock(host, mmc_sdio_get_max_clock(card));
/* * Switch to wider bus (if supported). */ err = sdio_enable_4bit_bus(card);
high-speed:
/* * Enable SDIO/combo card's high-speed mode. Return 0/1 if [not]supported. */ staticintsdio_enable_hs(struct mmc_card *card) { int ret;
ret = mmc_sdio_switch_hs(card, true); if (ret <= 0 || card->type == MMC_TYPE_SDIO) return ret;
先test是否支持then切换:
/* * Test if the card supports high-speed mode and, if so, switch to it. */ staticintmmc_sdio_switch_hs(struct mmc_card *card, int enable) { int ret; u8 speed;
if (!(card->host->caps & MMC_CAP_SD_HIGHSPEED)) return0;
if (!card->cccr.high_speed) return0;
ret = mmc_io_rw_direct(card, 0, 0, SDIO_CCCR_SPEED, 0, &speed); //tj:read if (ret) return ret;
if (enable) speed |= SDIO_SPEED_EHS; else speed &= ~SDIO_SPEED_EHS;
ret = mmc_io_rw_direct(card, 1, 0, SDIO_CCCR_SPEED, speed, NULL); //tj:write if (ret) return ret;
return1; }
4-bit:
staticintsdio_enable_4bit_bus(struct mmc_card *card) { int err;
if (card->type == MMC_TYPE_SDIO) err = sdio_enable_wide(card);
先test是否支持then配置4-bit:
staticintsdio_enable_wide(struct mmc_card *card) { int ret; u8 ctrl;
if (!(card->host->caps & MMC_CAP_4_BIT_DATA)) return0;
if (card->cccr.low_speed && !card->cccr.wide_bus) return0;
ret = mmc_io_rw_direct(card, 0, 0, SDIO_CCCR_IF, 0, &ctrl); //tj: read if (ret) return ret;
if ((ctrl & SDIO_BUS_WIDTH_MASK) == SDIO_BUS_WIDTH_RESERVED) pr_warn("%s: SDIO_CCCR_IF is invalid: 0x%02x\n", mmc_hostname(card->host), ctrl);
/* set as 4-bit bus width */ ctrl &= ~SDIO_BUS_WIDTH_MASK; ctrl |= SDIO_BUS_WIDTH_4BIT;
ret = mmc_io_rw_direct(card, 1, 0, SDIO_CCCR_IF, ctrl, NULL); //tj: write if (ret) return ret;
return1; }
Done.
BTW: Mobile bootloader seems do not support SDIO card, but i can:]