+ clk |= SDHCI_CLOCK_CARD_EN;
+ sdhci_writew(host, clk, SDHCI_CLOCK_CONTROL);
+}
+
+static int arasan_sdhci_execute_tuning(struct mmc *mmc, u8 opcode)
+{
+ struct mmc_cmd cmd;
+ struct mmc_data data;
+ u32 ctrl;
+ struct sdhci_host *host;
+ struct arasan_sdhci_priv *priv = dev_get_priv(mmc->dev);
+ char tuning_loop_counter = SDHCI_TUNING_LOOP_COUNT;
+ u8 deviceid;
+
+ debug("%s\n", __func__);
+
+ host = priv->host;
+ deviceid = priv->deviceid;
+
+ ctrl = sdhci_readw(host, SDHCI_HOST_CTRL2);
+ ctrl |= SDHCI_CTRL_EXEC_TUNING;
+ sdhci_writew(host, ctrl, SDHCI_HOST_CTRL2);
+
+ mdelay(1);
+
+ arasan_zynqmp_dll_reset(host, deviceid);
+
+ sdhci_writel(host, SDHCI_INT_DATA_AVAIL, SDHCI_INT_ENABLE);
+ sdhci_writel(host, SDHCI_INT_DATA_AVAIL, SDHCI_SIGNAL_ENABLE);
+
+ do {
+ cmd.cmdidx = opcode;
+ cmd.resp_type = MMC_RSP_R1;
+ cmd.cmdarg = 0;
+
+ data.blocksize = 64;
+ data.blocks = 1;
+ data.flags = MMC_DATA_READ;
+
+ if (tuning_loop_counter-- == 0)
+ break;
+
+ if (cmd.cmdidx == MMC_CMD_SEND_TUNING_BLOCK_HS200 &&
+ mmc->bus_width == 8)
+ data.blocksize = 128;
+
+ sdhci_writew(host, SDHCI_MAKE_BLKSZ(SDHCI_DEFAULT_BOUNDARY_ARG,
+ data.blocksize),
+ SDHCI_BLOCK_SIZE);
+ sdhci_writew(host, data.blocks, SDHCI_BLOCK_COUNT);
+ sdhci_writew(host, SDHCI_TRNS_READ, SDHCI_TRANSFER_MODE);
+
+ mmc_send_cmd(mmc, &cmd, NULL);
+ ctrl = sdhci_readw(host, SDHCI_HOST_CTRL2);
+
+ if (cmd.cmdidx == MMC_CMD_SEND_TUNING_BLOCK)
+ udelay(1);
+
+ } while (ctrl & SDHCI_CTRL_EXEC_TUNING);
+
+ if (tuning_loop_counter < 0) {
+ ctrl &= ~SDHCI_CTRL_TUNED_CLK;
+ sdhci_writel(host, ctrl, SDHCI_HOST_CTRL2);
+ }
+
+ if (!(ctrl & SDHCI_CTRL_TUNED_CLK)) {
+ printf("%s:Tuning failed\n", __func__);
+ return -1;
+ }
+
+ udelay(1);
+ arasan_zynqmp_dll_reset(host, deviceid);
+
+ /* Enable only interrupts served by the SD controller */
+ sdhci_writel(host, SDHCI_INT_DATA_MASK | SDHCI_INT_CMD_MASK,
+ SDHCI_INT_ENABLE);
+ /* Mask all sdhci interrupt sources */
+ sdhci_writel(host, 0x0, SDHCI_SIGNAL_ENABLE);