]> git.ipfire.org Git - thirdparty/u-boot.git/commitdiff
Xilinx: ARM: mmc: zynq: Add SD SWITCH_FUNC command support
authorJagannadha Sutradharudu Teki <jaganna@xilinx.com>
Wed, 5 Sep 2012 14:39:38 +0000 (20:09 +0530)
committerJohn Linn <john.linn@xilinx.com>
Mon, 10 Sep 2012 14:42:40 +0000 (07:42 -0700)
This patch adds support to handle the SWITCH_FUNC command on
sd driver.

Card can switch to high speed mode if both host and card
support. Reference system clock for SD controller is assumed
as 50MHz.

Signed-off-by: Jagannadha Sutradharudu Teki <jaganna@xilinx.com>
drivers/mmc/zynq_mmc.c
drivers/mmc/zynq_mmc.h

index 6d237a0e98f74be94f5136388e9699b0aee45ff7..b131d82c476b41719586f22ae17fb837cf763480 100644 (file)
@@ -243,9 +243,9 @@ static int zynq_sdh_request(struct mmc *mmc, struct mmc_cmd *cmd,
        cmd->response[0] = 0;
        cmdreg = make_command(cmd->cmdidx);
 
-       /* exit if command is SWITCH_FUNC, as it currently not supporting */
+       /* append the data if the command is SWITCH_FUNC */
        if (data && (data->flags & MMC_DATA_READ) && (cmd->cmdidx == 6))
-               return result;
+               cmdreg |= SD_CMD_DATA;
 
        /* Wait until the device is willing to accept commands */
        do {
@@ -383,13 +383,46 @@ exit:
 
 static void zynq_sdh_set_ios(struct mmc *mmc)
 {
-       u16 sdhci_clkctrl;
+       u16 clk, sdhci_clkctrl;
 
        debug("%s: voltages: 0x%x clock: 0x%x bus_width: 0x%x\n",
                __func__, mmc->voltages, mmc->clock, mmc->bus_width);
 
        sdhci_clkctrl = sd_in16(SD_HOST_CTRL_R);
 
+       /* Configure the clock 50MHz system REFF clock*/
+       if (mmc->clock) {
+               u32 div;
+
+               for (div = 1; div < 256; div *= 2) {
+                       if ((SD_REFF_CLK_50M / div) <= mmc->clock)
+                               break;
+               }
+               div >>= 1;
+
+               /* Disable SD clock and internal clock */
+               clk = sd_in16(SD_CLK_CTL_R);
+               clk &= ~(SD_CLK_SD_EN|SD_CLK_INT_EN);
+               sd_out16(SD_CLK_CTL_R, clk);
+
+               /* Enable Internal clock and wait for it to stablilize */
+               clk = (div << SD_DIV_SHIFT) | SD_CLK_INT_EN;
+               sd_out16(SD_CLK_CTL_R, clk);
+               do {
+                       clk = sd_in16(SD_CLK_CTL_R);
+               } while (!(clk & SD_CLK_INT_STABLE));
+
+               /* Enable SD clock */
+               clk |= SD_CLK_SD_EN;
+               sd_out16(SD_CLK_CTL_R, clk);
+
+               if (!div)
+                       /* Enable high speed mode in controller */
+                       sdhci_clkctrl |= SD_HOST_HS;
+               else
+                       sdhci_clkctrl &= ~SD_HOST_HS;
+       }
+
        /* Configure the bus_width */
        if (mmc->bus_width == 4)
                sdhci_clkctrl |= SD_HOST_4BIT;
@@ -426,7 +459,7 @@ int zynq_mmc_init(bd_t *bd)
        mmc->set_ios = zynq_sdh_set_ios;
        mmc->init = zynq_sdh_init;
 
-       mmc->host_caps = MMC_MODE_4BIT;
+       mmc->host_caps = MMC_MODE_4BIT | MMC_MODE_HS | MMC_MODE_HS_52MHz;
 
        mmc->voltages = MMC_VDD_32_33 | MMC_VDD_33_34;
         
index 3000990382d5685d08eed32809880c40ea880849..dd14dcb15b502f5cd9f5a9851b0b9403f129a225 100644 (file)
@@ -77,6 +77,9 @@
 #define  SD_CLK_INT_STABLE   0x0002
 #define  SD_CLK_INT_EN       0x0001
 
+#define SD_REFF_CLK_50M                50000000
+#define SD_HOST_HS             0x4
+
 #define SD_TIMEOUT_CTL_R     0x2E
 
 #define SD_SOFT_RST_R        0x2F