UPGRADE YOUR BROWSER

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!

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

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

Hi.

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>

ZynqMP> fdt addr 0x7fe82490

ZynqMP> fdt print /amba/sdhci@ff160000
sdhci@ff160000 {
    u-boot,dm-pre-reloc;
    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>

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
ZynqMP>
0 Kudos
1 Reply
Observer andrei.hres
Observer
919 Views
Registered: ‎03-18-2019

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

Hi.
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:
u-boot-xlnx/drivers/mmc/sdhci.c
u-boot-xlnx/drivers/mmc/zynq_sdhci.c
u-boot-xlnx/drivers/mmc/mmc-uclass.c
u-boot-xlnx/drivers/mmc/mmc.c
u-boot-xlnx/include/mmc.h

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?

 /u-boot-xlnx/drivers/mmc/mmc-uclass.c 

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; }

 /u-boot-xlnx/drivers/mmc/zynq_sdhci.c 

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 |
		       SDHCI_QUIRK_BROKEN_R1B;

#ifdef CONFIG_ZYNQ_HISPD_BROKEN
	host->quirks |= SDHCI_QUIRK_BROKEN_HISPD_MODE;
#endif

	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,
			      CONFIG_ZYNQ_SDHCI_MIN_FREQ);

	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