static void sdhci_snps_set_clock(struct sdhci_host *host, unsigned int clock) { u16 clk; u32 reg, vendor_ptr; vendor_ptr = sdhci_readw(host, SDHCI_VENDOR_PTR_R); /* Disable software managed rx tuning */ reg = sdhci_readl(host, (SDHC_AT_CTRL_R + vendor_ptr)); reg &= ~SDHC_SW_TUNE_EN; sdhci_writel(host, reg, (SDHC_AT_CTRL_R + vendor_ptr)); if (clock <= 52000000) { sdhci_set_clock(host, clock); } else { /* Assert reset to MMCM */ reg = sdhci_readl(host, (SDHC_GPIO_OUT + vendor_ptr)); reg |= SDHC_CCLK_MMCM_RST; sdhci_writel(host, reg, (SDHC_GPIO_OUT + vendor_ptr)); /* Configure MMCM */ if (clock == 100000000) { sdhci_writel(host, DIV_REG_100_MHZ, SDHC_MMCM_DIV_REG); sdhci_writel(host, CLKFBOUT_100_MHZ, SDHC_MMCM_CLKFBOUT); } else { sdhci_writel(host, DIV_REG_200_MHZ, SDHC_MMCM_DIV_REG); sdhci_writel(host, CLKFBOUT_200_MHZ, SDHC_MMCM_CLKFBOUT); } /* De-assert reset to MMCM */ reg = sdhci_readl(host, (SDHC_GPIO_OUT + vendor_ptr)); reg &= ~SDHC_CCLK_MMCM_RST; sdhci_writel(host, reg, (SDHC_GPIO_OUT + vendor_ptr)); /* Enable clock */ clk = SDHCI_PROG_CLOCK_MODE | SDHCI_CLOCK_INT_EN | SDHCI_CLOCK_CARD_EN; sdhci_writew(host, clk, SDHCI_CLOCK_CONTROL); } }
void sdhci_set_ios(struct mmc *mmc) { u32 ctrl; struct sdhci_host *host = (struct sdhci_host *)mmc->priv; if (host->set_control_reg) host->set_control_reg(host); if (mmc->clock != host->clock) sdhci_set_clock(mmc, mmc->clock); /* Set bus width */ ctrl = sdhci_readb(host, SDHCI_HOST_CONTROL); if (mmc->bus_width == 8) { ctrl &= ~SDHCI_CTRL_4BITBUS; if ((SDHCI_GET_VERSION(host) >= SDHCI_SPEC_300) || (host->quirks & SDHCI_QUIRK_USE_WIDE8)) ctrl |= SDHCI_CTRL_8BITBUS; } else { if (SDHCI_GET_VERSION(host) >= SDHCI_SPEC_300) ctrl &= ~SDHCI_CTRL_8BITBUS; if (mmc->bus_width == 4) ctrl |= SDHCI_CTRL_4BITBUS; else ctrl &= ~SDHCI_CTRL_4BITBUS; } #if 0 if (mmc->clock > 26000000) ctrl |= SDHCI_CTRL_HISPD; else #endif ctrl &= ~SDHCI_CTRL_HISPD; if (host->quirks & SDHCI_QUIRK_NO_HISPD_BIT) ctrl &= ~SDHCI_CTRL_HISPD; sdhci_writeb(host, ctrl, SDHCI_HOST_CONTROL); }
static void sdhci_reset(struct sdhci_slot *slot, uint8_t mask) { int timeout; if (slot->quirks & SDHCI_QUIRK_NO_CARD_NO_RESET) { if (!(RD4(slot, SDHCI_PRESENT_STATE) & SDHCI_CARD_PRESENT)) return; } /* Some controllers need this kick or reset won't work. */ if ((mask & SDHCI_RESET_ALL) == 0 && (slot->quirks & SDHCI_QUIRK_CLOCK_BEFORE_RESET)) { uint32_t clock; /* This is to force an update */ clock = slot->clock; slot->clock = 0; sdhci_set_clock(slot, clock); } if (mask & SDHCI_RESET_ALL) { slot->clock = 0; slot->power = 0; } WR1(slot, SDHCI_SOFTWARE_RESET, mask); if (slot->quirks & SDHCI_QUIRK_WAITFOR_RESET_ASSERTED) { /* * Resets on TI OMAPs and AM335x are incompatible with SDHCI * specification. The reset bit has internal propagation delay, * so a fast read after write returns 0 even if reset process is * in progress. The workaround is to poll for 1 before polling * for 0. In the worst case, if we miss seeing it asserted the * time we spent waiting is enough to ensure the reset finishes. */ timeout = 10000; while ((RD1(slot, SDHCI_SOFTWARE_RESET) & mask) != mask) { if (timeout <= 0) break; timeout--; DELAY(1); } } /* Wait max 100 ms */ timeout = 10000; /* Controller clears the bits when it's done */ while (RD1(slot, SDHCI_SOFTWARE_RESET) & mask) { if (timeout <= 0) { slot_printf(slot, "Reset 0x%x never completed.\n", mask); sdhci_dumpregs(slot); return; } timeout--; DELAY(10); } }