板子从SD卡启动,Uboot阶段可以正常识别并读出内核,SD是ok的,板子的eSDHC控制器也是ok的,到了内核初始化部分报错:
sdhci-esdhc 2140000.esdhc: Adding to iommu group 4
mmc0: SDHCI controller on 2140000.esdhc [2140000.esdhc] using ADMA 64-bit
mmc0: error -110 whilst initialising SD card
drivers/mmc/core/sd.c,省略不相关代码,mmc_sd_init_card()执行错误。
/*
* Starting point for SD card init.
*/
int mmc_attach_sd(struct mmc_host *host)
{
int err;
u32 ocr, rocr;
WARN_ON(!host->claimed);
...
/*
* Detect and init the card.
*/
err = mmc_sd_init_card(host, rocr, NULL);
if (err)
goto err;
...
err:
mmc_detach_bus(host);
pr_err("%s: error %d whilst initialising SD card\n",
mmc_hostname(host), err);
return err;
}
mmc_sd_get_cid(),获取能力出错。
/*
* Handle the detection and initialisation of a card.
*
* In the case of a resume, "oldcard" will contain the card
* we're trying to reinitialise.
*/
static int mmc_sd_init_card(struct mmc_host *host, u32 ocr,
struct mmc_card *oldcard)
{
struct mmc_card *card;
int err;
u32 cid[4];
u32 rocr = 0;
bool v18_fixup_failed = false;
WARN_ON(!host->claimed);
retry:
err = mmc_sd_get_cid(host, ocr, cid, &rocr);
if (err)
return err;
...
}
/*
* Fetch CID from card.
*/
int mmc_sd_get_cid(struct mmc_host *host, u32 ocr, u32 *cid, u32 *rocr)
{
int err;
u32 max_current;
int retries = 10;
u32 pocr = ocr;
try_again:
if (!retries) {
ocr &= ~SD_OCR_S18R;
pr_warn("%s: Skipping voltage switch\n", mmc_hostname(host));
}
/*
* Since we're changing the OCR value, we seem to
* need to tell some cards to go back to the idle
* state. We wait 1ms to give cards time to
* respond.
*/
mmc_go_idle(host);
/*
* If SD_SEND_IF_COND indicates an SD 2.0
* compliant card and we should set bit 30
* of the ocr to indicate that we can handle
* block-addressed SDHC cards.
*/
err = mmc_send_if_cond(host, ocr);
if (!err)
ocr |= SD_OCR_CCS;
/*
* If the host supports one of UHS-I modes, request the card
* to switch to 1.8V signaling level. If the card has failed
* repeatedly to switch however, skip this.
*/
if (retries && mmc_host_uhs(host))
ocr |= SD_OCR_S18R;
/*
* If the host can supply more than 150mA at current voltage,
* XPC should be set to 1.
*/
max_current = sd_get_host_max_current(host);
if (max_current > 150)
ocr |= SD_OCR_XPC;
//第一次执行mmc_send_app_op_cond没有问题:ocr = 0x41200000, *rocr = 0xc1ff8000
//第二次执行出了问题,超时
err = mmc_send_app_op_cond(host, ocr, rocr);
if (err)
return err;
/*
* In case CCS and S18A in the response is set, start Signal Voltage
* Switch procedure. SPI mode doesn't support CMD11.
*/
if (!mmc_host_is_spi(host) && rocr &&
((*rocr & 0x41000000) == 0x41000000)) { //第一次执行完mmc_send_app_op_cond后,*rcor的bit30 CCS 和bit24 S18A置位
err = mmc_set_uhs_voltage(host, pocr);
if (err == -EAGAIN) {
/*
* mmc_set_uhs_voltage()函数返回了-EAGAIN,进去跟踪后,发现,host设置电压信号没问题,但是检测到sd卡的四个数据位都是低电平,表示sd卡切换电压失败
*/
retries--;
goto try_again;
} else if (err) {
retries = 0;
goto try_again;
}
}
err = mmc_send_cid(host, cid);
return err;
}
问题找到了,由于SDHC控制器支持1.8V电平,初始化SD卡时,得知SD也支持1.8V操作,所以像其发送切换电压的命令,但是切换失败。再次尝试初始化时,已不能从SD卡正确获取信息,命令执行超时。
根本原因:SDHC控制器和SD卡座之间添加了电平转换芯片,SDHC的工作电压为1.8V,SD卡座的工作电压为3.3V,SD卡切换为1.8V操作模式时,肯定无法正常工作,因为外部电压是3.3V。
参考文档Documentation/devicetree/bindings/mmc/mmc-controller.yaml
,在SDHC控制在设备树节点中添加属性no-1-8-v
,如下:
no-1-8-v:
$ref: /schemas/types.yaml#/definitions/flag
description:
When specified, denotes that 1.8V card voltage is not supported
on this system, even if the controller claims it.
&esdhc0 {
sd-uhs-sdr104;
sd-uhs-sdr50;
sd-uhs-sdr25;
sd-uhs-sdr12;
no-1-8-v;
status = "okay";
};