Showing results for 
Show  only  | Search instead for 
Did you mean: 
Not applicable

Zynq SDIO via EMIO

Is there anyone using Zynq SDIO via EMIO?


Now examining SD access via EMIO, but correct access could not be confirmed.


According to reading sdio register, it seems to occur command CRC error (17 bit, Normal_interrupt_status_Errro_interrupt_status).


I'v alrady been checked eratta information, but not available.


Are there any other cautions for using SDIO via EMIO?

Should it be required any constraints in PL?







0 Kudos
46 Replies
Registered: ‎11-09-2013

OK, I will try to setup with CLK, CMD and DATA[0:1] (4 channel scope only) later today.


Can you clarify on 'feedback clock needs to be connected internally in the PL'? From my understanding, that is what I am doing: the ports on the PS7 IP:




are connected to the same net and I can see that in schematic view. It sounds like perhaps I need to be referencing that net name you have listed there directly somehow? I have a top-level wrapper around the auto-generated block design wrapper, which when I follow it down, is exposing the CLK and FB ports of the PS7 IP.


I've attached two screenshots of the synthesized schematic.

0 Kudos
Registered: ‎11-09-2013

Ah sorry, I cannot edit, but I chopped off the top of the first screenshot; it runs directly to 'SD0_clk'.
0 Kudos
Xilinx Employee
Xilinx Employee
Registered: ‎01-09-2013

Yes that is ok what you are doing for the feedback clock.


I will wait for the scope shot and let us know if the interface worked fine with the added contraints and the WP connected to GND.



0 Kudos
Registered: ‎11-09-2013

habibe -


I am working on the constraints now; those look like UCF / ISE constraints, correct? Are the below equivalent XDC constraints (or part of them)?


create_clock -period 10.000 -name sdio_pin_groups -waveform {5.000 5.000} [get_ports {io_SD_CMD io_SD_DATA[0] io_SD_DATA[1] io_SD_DATA[2] io_SD_DATA[3] o_CLK_SD}]


If you can let me know the XDC/Tcl versions of those UCF constraints, I will get a bitstream built and test it. Is your thinking that perhaps only my clocks are constrained, and the entirety of the interface must be?

0 Kudos
Registered: ‎11-09-2013

I did "play" with the constraints some, and that caused different errors in Linux, leading me to believe that it is some issues with constraints / timing I am not setting properly. I know the above posters in this thread respun to use MIO over EMIO, but hopefully I can find a working set of constraints (or Xilinx can provide me an example project / set of constraints) that I can share / post on my site to help others that are utilizing EMIO in their designs.


Going to go over the UG for Constraints in Vivado again to see what I need to do to match the TIMESPECs posted from habibe.

0 Kudos
Xilinx Employee
Xilinx Employee
Registered: ‎01-09-2013



Can you capture for me the SDIO interface timing with the scope? (data, cmd, clk)

I want to see the timing that you are having on your board with these signals.

And I can post tricks that have used to get the sdio to work through the emio but I want to make sure that you are seeing the same kind of timing on your side.




0 Kudos
Registered: ‎10-30-2013

Has there been any update on the issue? We got the SD Card working, but only in 1-bit mode. 4-bit throws error -84. We also had to route the FB_CLK.

0 Kudos
Registered: ‎11-07-2013

I've finally had some success.


Here are some of my findings:

I tried 1-bit mode, that didn't seem to help.


I tried to drastically slow down the clock speed all the way to 2 MHz without success.  I put a small hack in the Linux kernel in drivers/mmc/core/core.c __mmc_set_clock() function.  I would modify the passed in hz variable before it was used to configure the clock.  Changing the clock frequency in the dts didn't seem to do anything because the driver is querying the card and many of the device tree settings are ignored.  I was using an O-scope to measure the clock frequency when testing this.


What finally worked the best for me, was hacking the kernel so that when the card returns back the modes it supports, changing those values to lower speed modes.  I've tried Delkin, SwissBit, and SanDisk cards in mine.  The cards would tell the kernel to operate them in the High Speed mode (50MHz).  I added an early "return 0;" from drivers/mmc/core/sd.c mmc_sd_switch_hs() to trick the kernel into only running them at Default Speed.  Linux would only try to operate the clock at 25MHz and the data was transitioning on the falling clock edges rather than the rising clock edges of the high speed mode. 

Registered: ‎11-07-2013

Just a quick update to anyone else who runs into this issue.


We were not successful at running this at full default speed mode (100MHz / 4 = 25 MHz).  Not sure how much FPGA routing is affecting us and what not.  But we were successful at 22.5 MHz (90 MHz / 4) using the default speed mode I described in previous post.

0 Kudos
Registered: ‎03-27-2014

Thanks mwales,

I followed your directions and now I am able to access the SD card at 15MHz.

0 Kudos
Registered: ‎01-31-2013

Thanks, mwales and guys who shared the info. Now it works correctly on zynq7030.

My experience:

First thing I faced was the absence of the SD clock at the output. It turned out it was the Vivado's issue. I recreated the project and it partially helped, I got the clock but data signals still kept silence. In this iteration I made the whole SD port external in the Block Design manager and wrote my own top level wrapper on the vivado's "Create HDL wrapper" ;)

I checked the T signal inversion issue and found it was solved in Vivado 2014.2 I used. The workaround had been already in there. Then I took out each individual SD wire (_0, _I, _T signals for data, cmd and others) to the top level and added the IOBUFs manually. It helped. The u-boot and the Linux could recognize 1 of 3 SD cards I had.

Here I must say that the SD clock speed was set at 25MHz in Vivado and clock feedback was connected to the clock output from the very beginning.

Then I started playing with the speed in u-boot. As was mentioned here in the topic the speed is hardcoded in u-boot. There are max and min clock frequecy settings. The ug585 says: "Additionally, it might be necessary to restrict the SDIO to operate in full or low speed modes, refer to the data sheet for frequency and timing values". So I set 25MHz for max and 1MHz for min freq in /drivers/mmc/zynq_sdhc.c, add_sdhci(host, 25000000, 1000000); function.

The last thing I did was the Linux hack as mwales shared in the previous post.

Now, I can boot from SD, mount SD in Linux and everything. Thanks guys!
Registered: ‎10-28-2007

Gidday there,


I have attached a patch for the sdhci-of-arasan driver that will look for a DTS property to indicate that the SD signals have been routed through EMIO.  Then it will remove the capability for High-Speed before the main Linux sdhci_add_host is called.


For it to work, add the following to your ps7_sd1 DTS entry.


xlnx,emio = <1>;

This has been tested with a custom zynq-7020, but since an sdhci_reset() is not performed prior to reading the capabilities register, I can imagine some entertaining corner cases where Linux is restarted while the SDHCI is in a funny state.


Suggestions welcome.





From d122312c74986927ac2002a6e62841fb6123587c Mon Sep 17 00:00:00 2001
From: Joshua Lamorie <>
Date: Fri, 25 Jul 2014 14:13:47 -0400
Subject: [PATCH] SDHCI Arasan quirk for Zynq EMIO

Added check in DTS for a flag indicating that the SD signals for Zynq's SDHCI
host have been routed through the EMIO interface instead of the MIO.  When
connected directly to MIO pins, the SDHCI can run at 50MHz.  When routed
through the EMIO interconnect, the maximum SD clock is 25MHz.

Signed-off-by: Joshua Lamorie <>
 drivers/mmc/host/sdhci-of-arasan.c | 25 +++++++++++++++++++++++++
 1 file changed, 25 insertions(+)

diff --git a/drivers/mmc/host/sdhci-of-arasan.c b/drivers/mmc/host/sdhci-of-arasan.c
index f7c7cf6..9f1b531 100644
--- a/drivers/mmc/host/sdhci-of-arasan.c
+++ b/drivers/mmc/host/sdhci-of-arasan.c
@@ -20,8 +20,11 @@
 #include <linux/module.h>
+#include <linux/of.h>
 #include "sdhci-pltfm.h"
+#include "sdhci.h" // to read capabilities from the host
 #define CLK_CTRL_TIMEOUT_SHIFT         16
@@ -170,6 +173,27 @@ static int sdhci_arasan_probe(struct platform_device *pdev)
        pltfm_host->priv = sdhci_arasan;
        pltfm_host->clk = clk_xin;
+       {
+               struct device_node *np = pdev->dev.of_node;
+               u32 emio = 0;
+               if (of_device_is_available(np) && of_property_read_u32(np,"xlnx,emio",&emio) == 0) {
+                       if (emio) {
+                               dev_info(&pdev->dev, "SD routed through EMIO: Disabling SDHCI High-speed\n");
+                               /* The SD lines have been routed through the Zynq EMIO interface
+                                * which is limited to 25MHz.  Spoof the SDHCI caps to remove
+                                * high-speed support.
+                                */
+                               host->quirks |= SDHCI_QUIRK_MISSING_CAPS;
+                               // WARNING: This may fail because sdhci_reset() is not called before
+                               host->caps = sdhci_readl(host, SDHCI_CAPABILITIES) & ~(SDHCI_CAN_DO_HISPD);
+                               host->caps1 = sdhci_readl(host, SDHCI_CAPABILITIES_1);
+                       } else {
+                               dev_info(&pdev->dev, "SD routed through MIO: SDHCI High-speed enabled\n");
+                       }
+               }
+       }
        ret = sdhci_add_host(host);
        if (ret) {
                dev_err(&pdev->dev, "platform register failed (%u)\n", ret); --


Note: I have modified the patch with a few improvements since it was first posted.

0 Kudos
Registered: ‎02-17-2013

Hi all,


I was also suffering by same problem that EMMC was not working.

Fortunately it started working after SDIO_CLK and SDIO_CLK_FB is connected internally in FPGA in top wrapper file.

I am usuing .TCL file for full project build.

TCL file is modifying my wrapper evrytime.Is there any solution that this connection can be written in TCL file?




Nikhil M 

0 Kudos
Registered: ‎09-26-2014

Does anyone have an example vivado/sdk design that works for the Zynq SDIO via EMIO?


I have tried all the things described in this post and other forums and I cannot get it to work. In a variety of different methods I get 1 of 2 scenarios either:

1) I get a status = 1 i.e. XST_FAILURE from "Status = XSdPs_CmdTransfer(InstancePtr, CMD6, Arg, 1U);"


2) It jumps into the XST_FAILURE path straight after the previous command(if it was a success)

     * Check for transfer complete
     * Polling for response for now
    do {
        StatusReg = XSdPs_ReadReg16(InstancePtr->Config.BaseAddress,
        if ((StatusReg & XSDPS_INTR_ERR_MASK) != 0U) {
            /* Write to clear error bits */
            Status = XST_FAILURE;
            goto RETURN_PATH;
    } while ((StatusReg & XSDPS_INTR_TC_MASK) == 0U);


Really hoping somebody can help as I'm out of ideas now.

p.s. I using a pmod sd card that means the SD interface is setup as 3.3V.

0 Kudos
Registered: ‎02-20-2014

After dealing with SDIO via EMIO difficulties for more than one week, this thread has helped a lot to find out what exactly the problem is. Of course I have tried to lower the speed to 25 MHz and less, just to find that particularly writing to the card is error prone (CMD 24/25 returning with error code -84 in Linux). So this is the result of my efforts, perhaps it is useful for anyone.

It seems like SDIO via EMIO is violating the hold time requirements of the SD card when operating in high speed (HS) mode. HS mode usually refers to bus speed of 50 MHz. Simply reducing the clock speed might not be sufficient though if the SD card still advertises HS capabilities! It causes the host controller to present the data on the the rising clock edge instead of the falling edge in low and default (full) speed mode. In HS mode, the data signals transition too early for the card to be sampled correctly, no matter if 50 or 25 MHz. That's why writing data to the card has always failed in my case. If one can limit the clock frequency to <= 25 MHz AND bus mode to default speed, all is fine. But U-Boot and Linux drivers do not seem to respect this and make it difficult to force the SD card and host controller to default speed without patching the driver which is a PITA.

So instead of going down this road, I decided to analyze what is causing the timing violations in the first place. I checked the PL net delays for clock and data via report_property / get_net_delays just to find nothing suspicious. Routing the SDIo interface to the SelectIO pins was always OK without significant variation across several runs. But measuring the bus with the scope and checking the SD card specifications for HS mode, the clock was too early compared to the CMD and DATA signals.

HS mode, no delay. yellow: CLK, red: CMD, blue: DATA [0]HS mode, no delay. yellow: CLK, red: CMD, blue: DATA [0]

So I decided to delay these signals, even though the Zynq TRM recommends to connect the SDIO EMIO interface directly to the SelectIO pins. I discovered that the XC7Z010/020 only feature HR banks and thus no ODELAY2E is available. :/ So I choose the "dirty" way of delaying the signals by ~ 8 ns using a high speed clock and a shift register. (It's important to do this for each of the 10 tri-state / T and output / O signals of CMD and DATA. If you have the CLK routed back to a clock-capable input pin as CLK_FB, perhaps you can "abuse" it for the purpose of a delayed clock.) All of a sudden, the card started working reliably and the signals on the PCB looked correct now, independant of the bus mode and the clock frequency.

zynq_sdio_emio_delay.pngHS mode, delayed CMD & DATA. yellow: CLK, red: delayed CMD, blue: delayed DATA[0]HS mode, delayed CMD & DATA. yellow: CLK, red: delayed CMD, blue: delayed DATA[0]

It is important to note that also the host controller in the Zynq is critical with respect to hold timing violations in HS mode. This can easily mitigated by connecting the CLK signal directly to CLK_FB, so sampling happens some essential nanoseconds earlier.

Checking the SD write performance in Linux with dd conv=fsync resulted in speeds up to 9.2 MB/s which is pretty close to the 10 MB/s for a class 10 card. (This could also be achieved with default speed at 25 MHz, but for SD cards with better write performance HS mode could make a difference.)

Again, I have spent more than a week measuring all the signals, reading the SD and Zynq specs, checking the routing in the PL, and evaluating different option. Maybe it's not a "catch-all" solution for everybody, but in my case it works without modifying any driver or software (I consider it a HW hack).

Registered: ‎01-26-2018

This thread was very helpful in getting the SDIO over EMIO issues sorted out.  I thought I would add to the community knowledge by posting my "fix".  I used a clock feedback within the FPGA, with CLK, CMD, and D0-3 routed to an SDIO module.  Linux would autonegotiate the increase to high speed mode, causing the timing issues.  Digging into the core sdhci code on linux, it is possible to disable HS capabilities for the controller with a device-tree change:

&sdhci1 {
	status = "okay";
	max-frequency = <25000000>;
	sdhci-caps-mask = <0x0 0x00200000>;	/* turn off HISPD mode because we're using EMIO (see drivers/mmc/host/sdhci.h for list of capabilities mask values) */	

This will hopefully let someone replace a custom patch (as detailed earlier in this thread) and continue using an unpatched Xilinx kernel.

Registered: ‎05-26-2017

Thanks for posting your solution, it worked for me 

0 Kudos