We have detected your current browser version is not the latest one. Xilinx.com uses the latest web technologies to bring you the best online experience possible. Please upgrade to a Xilinx.com supported browser:Chrome, Firefox, Internet Explorer 11, Safari. Thank you!

Showing results for 
Search instead for 
Did you mean: 
Observer andrei.hres
Registered: ‎03-18-2019

U-Boot does not switch eMMC bus width to 8-bit mode


I have our custom board with xczu9eg. I use Vivado and PetaLinux v2018.2 tools. I need QSPI+eMMC boot mode. I have found that after booting Linux eMMC bus width is 4-bit. When I add bus-width property for device-tree (/plnx-project/project-spec/meta-user/recipes-bsp/device-tree/files/system-user.dtsi) It resolve the problem for Linux.

/* system-user.dtsi */

/include/ "system-conf.dtsi"
/ {

/* SD0 eMMC, 8-bit wide data bus */
/* non-removable; */
/* broken-mmc-highspeed; */
&sdhci0 {
        status = "okay";
        bus-width = <8>;
        clock-frequency = <200000000>;
        max-frequency = <200000000>;

In Linux the bus width for eMMC is 8-bit now.

But this does not resolve the problem with bus width in U-Boot. I see U-Boot understand my option " bus-width" in device-tree but it does not apply this option.

ZynqMP> bdinfo
arch_number = 0x00000000
boot_params = 0x00000000
DRAM bank   = 0x00000000
-> start    = 0x00000000
-> size     = 0x7FF00000
baudrate    = 115200 bps
TLB addr    = 0x7FEE0000
relocaddr   = 0x7FDF7000
reloc off   = 0x77DF7000
irq_sp      = 0x7DDB6DE0
sp start    = 0x7DDB6DE0
ARM frequency = 50 MHz
DSP frequency = 0 MHz
DDR frequency = 0 MHz
Early malloc usage: bd8 / 8000
fdt_blob = 000000007fe82490

ZynqMP> fdt addr 0x7fe82490

ZynqMP> fdt print /amba/sdhci@ff160000
sdhci@ff160000 {
    compatible = "xlnx,zynqmp-8.9a", "arasan,sdhci-8.9a";
    status = "okay";
    interrupt-parent = <0x00000004>;
    interrupts = <0x00000000 0x00000030 0x00000004>;
    reg = <0x00000000 0xff160000 0x00000000 0x00001000>;
    clock-names = "clk_xin", "clk_ahb";
    xlnx,device_id = <0x00000000>;
    #stream-id-cells = <0x00000001>;
    iommus = <0x00000009 0x00000870>;
    power-domains = <0x0000001c>;
    clocks = <0x00000003 0x00000036 0x00000003 0x0000001f>;
    clock-frequency = " ��";
    xlnx,mio_bank = <0x00000000>;
    max-frequency = " ��";
    bus-width = <0x00000008>;

ZynqMP> mmcinfo
Device: sdhci@ff160000
Manufacturer ID: 13
OEM: 14e
Name: Q2J55
Tran Speed: 200000000
Rd Block Len: 512
MMC version 5.0
High Capacity: Yes
Capacity: 7.1 GiB
Bus Width: 4-bit
Erase Group Size: 512 KiB
HC WP Group Size: 8 MiB
User Capacity: 7.1 GiB WRREL
Boot Capacity: 16 MiB ENH
RPMB Capacity: 4 MiB ENH
0 Kudos
1 Reply
Observer andrei.hres
Registered: ‎03-18-2019

Re: U-Boot does not switch eMMC bus width to 8-bit mode

I have tried U-Boot source code from https://github.com/Xilinx/u-boot-xlnx and https://github.com/u-boot/u-boot.git but I have got same result (eMMC bus width only 4-bit).
Then I have found function mmc_of_parse in u-boot-xlnx source code (u-boot-xlnx/drivers/mmc/mmc-uclass.c). I think It must initialize bus width in 8-bit mode (by reading "bus-width" property from device-tree) but this function has never been called.
I analyze source code from:

If I add call of mmc_of_parse function in arasan_sdhci_probe function then driver switch bus width to 8-bit mode.
I am confused driver (zynq_sdhci.c) is wrong or I do something wrong?


int mmc_of_parse(struct udevice *dev, struct mmc_config *cfg)
	int val;
// I have option "bus-width" 8 in device-tree val = dev_read_u32_default(dev, "bus-width", 1); switch (val) { case 0x8: cfg->host_caps |= MMC_MODE_8BIT; /* fall through */ case 0x4: cfg->host_caps |= MMC_MODE_4BIT; /* fall through */ case 0x1: cfg->host_caps |= MMC_MODE_1BIT; break; default: dev_err(dev, "Invalid \"bus-width\" value %u!\n", val); return -EINVAL; } /* f_max is obtained from the optional "max-frequency" property */ dev_read_u32(dev, "max-frequency", &cfg->f_max); if (dev_read_bool(dev, "cap-sd-highspeed")) cfg->host_caps |= MMC_CAP(SD_HS); if (dev_read_bool(dev, "cap-mmc-highspeed")) cfg->host_caps |= MMC_CAP(MMC_HS); if (dev_read_bool(dev, "sd-uhs-sdr12")) cfg->host_caps |= MMC_CAP(UHS_SDR12); if (dev_read_bool(dev, "sd-uhs-sdr25")) cfg->host_caps |= MMC_CAP(UHS_SDR25); if (dev_read_bool(dev, "sd-uhs-sdr50")) cfg->host_caps |= MMC_CAP(UHS_SDR50); if (dev_read_bool(dev, "sd-uhs-sdr104")) cfg->host_caps |= MMC_CAP(UHS_SDR104); if (dev_read_bool(dev, "sd-uhs-ddr50")) cfg->host_caps |= MMC_CAP(UHS_DDR50); if (dev_read_bool(dev, "mmc-ddr-1_8v")) cfg->host_caps |= MMC_CAP(MMC_DDR_52); if (dev_read_bool(dev, "mmc-ddr-1_2v")) cfg->host_caps |= MMC_CAP(MMC_DDR_52); if (dev_read_bool(dev, "mmc-hs200-1_8v")) cfg->host_caps |= MMC_CAP(MMC_HS_200); if (dev_read_bool(dev, "mmc-hs200-1_2v")) cfg->host_caps |= MMC_CAP(MMC_HS_200); if (dev_read_bool(dev, "mmc-hs400-1_8v")) cfg->host_caps |= MMC_CAP(MMC_HS_400); if (dev_read_bool(dev, "mmc-hs400-1_2v")) cfg->host_caps |= MMC_CAP(MMC_HS_400); return 0; }


static int arasan_sdhci_probe(struct udevice *dev)
	struct arasan_sdhci_plat *plat = dev_get_platdata(dev);
	struct mmc_uclass_priv *upriv = dev_get_uclass_priv(dev);
	struct arasan_sdhci_priv *priv = dev_get_priv(dev);
	struct sdhci_host *host;
	struct clk clk;
	unsigned long clock;
	int ret;

	host = priv->host;

	ret = clk_get_by_index(dev, 0, &clk);
	if (ret < 0) {
		dev_err(dev, "failed to get clock\n");
		return ret;

	clock = clk_get_rate(&clk);
	if (IS_ERR_VALUE(clock)) {
		dev_err(dev, "failed to get rate\n");
		return clock;

	debug("%s: CLK %ld\n", __func__, clock);

	ret = clk_enable(&clk);
	if (ret && ret != -ENOSYS) {
		dev_err(dev, "failed to enable clock\n");
		return ret;

	host->quirks = SDHCI_QUIRK_WAIT_SEND_CMD |


	if (priv->no_1p8)
		host->quirks |= SDHCI_QUIRK_NO_1_8_V;

	host->max_clk = clock;

	// This my code for read option from device-tree
	mmc_of_parse(dev, &plat->cfg);

	ret = sdhci_setup_cfg(&plat->cfg, host, plat->f_max,

	host->mmc = &plat->mmc;
	if (ret)
		return ret;
	host->mmc->priv = host;
	host->mmc->dev = dev;
	upriv->mmc = host->mmc;

	return sdhci_probe(dev);


0 Kudos