Add HW tuning support for SD host controller in SDR104 mode

Signed-off-by: Shirley Her <[email protected]>
---
Change in V1:
1. Add HW tuning for SDR104 mode instead of SW tuning
2. Change clock base to 208Mhz in SDR104 mode
3. Add CMD and DATA line reset after HW tuning command
---
 drivers/mmc/host/sdhci-pci-o2micro.c | 33 ++++++++++++++++++++++++----
 1 file changed, 29 insertions(+), 4 deletions(-)

diff --git a/drivers/mmc/host/sdhci-pci-o2micro.c 
b/drivers/mmc/host/sdhci-pci-o2micro.c
index ed3c605fcf0c..fa76748d8929 100644
--- a/drivers/mmc/host/sdhci-pci-o2micro.c
+++ b/drivers/mmc/host/sdhci-pci-o2micro.c
@@ -196,7 +196,7 @@ static void __sdhci_o2_execute_tuning(struct sdhci_host 
*host, u32 opcode)
 {
        int i;
 
-       sdhci_send_tuning(host, MMC_SEND_TUNING_BLOCK_HS200);
+       sdhci_send_tuning(host, opcode);
 
        for (i = 0; i < 150; i++) {
                u16 ctrl = sdhci_readw(host, SDHCI_HOST_CONTROL2);
@@ -305,10 +305,12 @@ static int sdhci_o2_execute_tuning(struct mmc_host *mmc, 
u32 opcode)
         * This handler only implements the eMMC tuning that is specific to
         * this controller.  Fall back to the standard method for other TIMING.
         */
-       if (host->timing != MMC_TIMING_MMC_HS200)
+       if ((host->timing != MMC_TIMING_MMC_HS200) &&
+               (host->timing != MMC_TIMING_UHS_SDR104))
                return sdhci_execute_tuning(mmc, opcode);
 
-       if (WARN_ON(opcode != MMC_SEND_TUNING_BLOCK_HS200))
+       if (WARN_ON((opcode != MMC_SEND_TUNING_BLOCK_HS200) &&
+                       (opcode != MMC_SEND_TUNING_BLOCK)))
                return -EINVAL;
        /*
         * Judge the tuning reason, whether caused by dll shift
@@ -342,6 +344,9 @@ static int sdhci_o2_execute_tuning(struct mmc_host *mmc, 
u32 opcode)
                sdhci_set_bus_width(host, current_bus_width);
        }
 
+       sdhci_reset(host, SDHCI_RESET_CMD);
+       sdhci_reset(host, SDHCI_RESET_DATA);
+
        host->flags &= ~SDHCI_HS400_TUNING;
        return 0;
 }
@@ -369,7 +374,6 @@ static void o2_pci_led_enable(struct sdhci_pci_chip *chip)
        scratch_32 |= O2_SD_LED_ENABLE;
        pci_write_config_dword(chip->pdev,
                               O2_SD_TEST_REG, scratch_32);
-
 }
 
 static void sdhci_pci_o2_fujin2_pci_init(struct sdhci_pci_chip *chip)
@@ -497,6 +501,10 @@ static void sdhci_o2_enable_clk(struct sdhci_host *host, 
u16 clk)
 static void sdhci_pci_o2_set_clock(struct sdhci_host *host, unsigned int clock)
 {
        u16 clk;
+       u8 scratch;
+       u32 scratch_32;
+       struct sdhci_pci_slot *slot = sdhci_priv(host);
+       struct sdhci_pci_chip *chip = slot->chip;
 
        host->mmc->actual_clock = 0;
 
@@ -505,6 +513,23 @@ static void sdhci_pci_o2_set_clock(struct sdhci_host 
*host, unsigned int clock)
        if (clock == 0)
                return;
 
+       if ((host->timing == MMC_TIMING_UHS_SDR104) && (clock == 200000000)) {
+               pci_read_config_byte(chip->pdev, O2_SD_LOCK_WP, &scratch);
+
+               scratch &= 0x7f;
+               pci_write_config_byte(chip->pdev, O2_SD_LOCK_WP, scratch);
+
+               pci_read_config_dword(chip->pdev, O2_SD_PLL_SETTING, 
&scratch_32);
+
+               if ((scratch_32 & 0xFFFF0000) != 0x2c280000)
+                       o2_pci_set_baseclk(chip, 0x2c280000);
+
+               pci_read_config_byte(chip->pdev, O2_SD_LOCK_WP, &scratch);
+
+               scratch |= 0x80;
+               pci_write_config_byte(chip->pdev, O2_SD_LOCK_WP, scratch);
+       }
+
        clk = sdhci_calc_clk(host, clock, &host->mmc->actual_clock);
        sdhci_o2_enable_clk(host, clk);
 }
-- 
2.25.1

Reply via email to