diff options
Diffstat (limited to 'drivers/mmc/host/sdhci-pci-o2micro.c')
-rw-r--r-- | drivers/mmc/host/sdhci-pci-o2micro.c | 39 |
1 files changed, 35 insertions, 4 deletions
diff --git a/drivers/mmc/host/sdhci-pci-o2micro.c b/drivers/mmc/host/sdhci-pci-o2micro.c index e2a846885902..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); } @@ -561,6 +586,12 @@ static int sdhci_pci_o2_probe_slot(struct sdhci_pci_slot *slot) slot->host->mmc_host_ops.get_cd = sdhci_o2_get_cd; } + if (chip->pdev->device == PCI_DEVICE_ID_O2_SEABIRD1) { + slot->host->mmc_host_ops.get_cd = sdhci_o2_get_cd; + host->mmc->caps2 |= MMC_CAP2_NO_SDIO; + host->quirks2 |= SDHCI_QUIRK2_PRESET_VALUE_BROKEN; + } + host->mmc_host_ops.execute_tuning = sdhci_o2_execute_tuning; if (chip->pdev->device != PCI_DEVICE_ID_O2_FUJIN2) |