/** * esdhc_readl_fixup - Fixup the value read from incompatible eSDHC register * to make it compatible with SD spec. * * @host: pointer to sdhci_host * @spec_reg: SD spec register address * @value: 32bit eSDHC register value on spec_reg address * * In SD spec, there are 8/16/32/64 bits registers, while all of eSDHC * registers are 32 bits. There are differences in register size, register * address, register function, bit position and function between eSDHC spec * and SD spec. * * Return a fixed up register value
*/ static u32 esdhc_readl_fixup(struct sdhci_host *host, int spec_reg, u32 value)
{ struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); struct sdhci_esdhc *esdhc = sdhci_pltfm_priv(pltfm_host);
u32 ret;
/* * The bit of ADMA flag in eSDHC is not compatible with standard * SDHC register, so set fake flag SDHCI_CAN_DO_ADMA2 when ADMA is * supported by eSDHC. * And for many FSL eSDHC controller, the reset value of field * SDHCI_CAN_DO_ADMA1 is 1, but some of them can't support ADMA, * only these vendor version is greater than 2.2/0x12 support ADMA.
*/ if ((spec_reg == SDHCI_CAPABILITIES) && (value & SDHCI_CAN_DO_ADMA1)) { if (esdhc->vendor_ver > VENDOR_V_22) {
ret = value | SDHCI_CAN_DO_ADMA2; return ret;
}
}
/* * The DAT[3:0] line signal levels and the CMD line signal level are * not compatible with standard SDHC register. The line signal levels * DAT[7:0] are at bits 31:24 and the command line signal level is at * bit 23. All other bits are the same as in the standard SDHC * register.
*/ if (spec_reg == SDHCI_PRESENT_STATE) {
ret = value & 0x000fffff;
ret |= (value >> 4) & SDHCI_DATA_LVL_MASK;
ret |= (value << 1) & SDHCI_CMD_LVL;
/* * Some controllers have unreliable Data Line Active * bit for commands with busy signal. This affects * Command Inhibit (data) bit. Just ignore it since * MMC core driver has already polled card status * with CMD13 after any command with busy siganl.
*/ if (esdhc->quirk_ignore_data_inhibit)
ret &= ~SDHCI_DATA_INHIBIT; return ret;
}
/* * DTS properties of mmc host are used to enable each speed mode * according to soc and board capability. So clean up * SDR50/SDR104/DDR50 support bits here.
*/ if (spec_reg == SDHCI_CAPABILITIES_1) {
ret = value & ~(SDHCI_SUPPORT_SDR50 | SDHCI_SUPPORT_SDR104 |
SDHCI_SUPPORT_DDR50); return ret;
}
if (spec_reg == SDHCI_TRANSFER_MODE) return pltfm_host->xfer_mode_shadow;
if (spec_reg == SDHCI_HOST_VERSION)
ret = value & 0xffff; else
ret = (value >> shift) & 0xffff; /* Workaround for T4240-R1.0-R2.0 eSDHC which has incorrect * vendor version and spec version information.
*/ if ((spec_reg == SDHCI_HOST_VERSION) &&
(esdhc->quirk_incorrect_hostver))
ret = (VENDOR_V_23 << SDHCI_VENDOR_VER_SHIFT) | SDHCI_SPEC_200; return ret;
}
/* * "DMA select" locates at offset 0x28 in SD specification, but on * P5020 or P3041, it locates at 0x29.
*/ if (spec_reg == SDHCI_HOST_CONTROL) { /* DMA select is 22,23 bits in Protocol Control Register */
dma_bits = (value >> 5) & SDHCI_CTRL_DMA_MASK; /* fixup the result */
ret &= ~SDHCI_CTRL_DMA_MASK;
ret |= dma_bits;
} return ret;
}
/** * esdhc_writel_fixup - Fixup the SD spec register value so that it could be * written into eSDHC register. * * @host: pointer to sdhci_host * @spec_reg: SD spec register address * @value: 8/16/32bit SD spec register value that would be written * @old_value: 32bit eSDHC register value on spec_reg address * * In SD spec, there are 8/16/32/64 bits registers, while all of eSDHC * registers are 32 bits. There are differences in register size, register * address, register function, bit position and function between eSDHC spec * and SD spec. * * Return a fixed up register value
*/ static u32 esdhc_writel_fixup(struct sdhci_host *host, int spec_reg, u32 value, u32 old_value)
{
u32 ret;
/* * Enabling IRQSTATEN[BGESEN] is just to set IRQSTAT[BGE] * when SYSCTL[RSTD] is set for some special operations. * No any impact on other operation.
*/ if (spec_reg == SDHCI_INT_ENABLE)
ret = value | SDHCI_INT_BLK_GAP; else
ret = value;
switch (spec_reg) { case SDHCI_TRANSFER_MODE: /* * Postpone this write, we must do it together with a * command write that is down below. Return old value.
*/
pltfm_host->xfer_mode_shadow = value; return old_value; case SDHCI_COMMAND:
ret = (value << 16) | pltfm_host->xfer_mode_shadow; return ret;
}
ret = old_value & (~(0xffff << shift));
ret |= (value << shift);
if (spec_reg == SDHCI_BLOCK_SIZE) { /* * Two last DMA bits are reserved, and first one is used for * non-standard blksz of 4096 bytes that we don't support * yet. So clear the DMA boundary bits.
*/
ret &= (~SDHCI_MAKE_BLKSZ(0x7, 0));
} return ret;
}
/* * eSDHC doesn't have a standard power control register, so we do * nothing here to avoid incorrect operation.
*/ if (spec_reg == SDHCI_POWER_CONTROL) return old_value; /* * "DMA select" location is offset 0x28 in SD specification, but on * P5020 or P3041, it's located at 0x29.
*/ if (spec_reg == SDHCI_HOST_CONTROL) { /* * If host control register is not standard, exit * this function
*/ if (host->quirks2 & SDHCI_QUIRK2_BROKEN_HOST_CONTROL) return old_value;
/* DMA select is 22,23 bits in Protocol Control Register */
dma_bits = (value & SDHCI_CTRL_DMA_MASK) << 5;
ret = (old_value & (~(SDHCI_CTRL_DMA_MASK << 5))) | dma_bits;
tmp = (value & (~SDHCI_CTRL_DMA_MASK)) |
(old_value & SDHCI_CTRL_DMA_MASK);
ret = (ret & (~0xff)) | tmp;
/* Prevent SDHCI core from writing reserved bits (e.g. HISPD) */
ret &= ~ESDHC_HOST_CONTROL_RES; return ret;
}
staticvoid esdhc_be_writew(struct sdhci_host *host, u16 val, int reg)
{ struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); struct sdhci_esdhc *esdhc = sdhci_pltfm_priv(pltfm_host); int base = reg & ~0x3;
u32 value;
u32 ret;
value = ioread32be(host->ioaddr + base);
ret = esdhc_writew_fixup(host, reg, val, value); if (reg != SDHCI_TRANSFER_MODE)
iowrite32be(ret, host->ioaddr + base);
/* Starting SW tuning requires ESDHC_SMPCLKSEL to be set * 1us later after ESDHC_EXTN is set.
*/ if (base == ESDHC_SYSTEM_CONTROL_2) { if (!(value & ESDHC_EXTN) && (ret & ESDHC_EXTN) &&
esdhc->in_sw_tuning) {
udelay(1);
ret |= ESDHC_SMPCLKSEL;
iowrite32be(ret, host->ioaddr + base);
}
}
}
staticvoid esdhc_le_writew(struct sdhci_host *host, u16 val, int reg)
{ struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); struct sdhci_esdhc *esdhc = sdhci_pltfm_priv(pltfm_host); int base = reg & ~0x3;
u32 value;
u32 ret;
value = ioread32(host->ioaddr + base);
ret = esdhc_writew_fixup(host, reg, val, value); if (reg != SDHCI_TRANSFER_MODE)
iowrite32(ret, host->ioaddr + base);
/* Starting SW tuning requires ESDHC_SMPCLKSEL to be set * 1us later after ESDHC_EXTN is set.
*/ if (base == ESDHC_SYSTEM_CONTROL_2) { if (!(value & ESDHC_EXTN) && (ret & ESDHC_EXTN) &&
esdhc->in_sw_tuning) {
udelay(1);
ret |= ESDHC_SMPCLKSEL;
iowrite32(ret, host->ioaddr + base);
}
}
}
staticvoid esdhc_be_writeb(struct sdhci_host *host, u8 val, int reg)
{ int base = reg & ~0x3;
u32 value;
u32 ret;
value = ioread32be(host->ioaddr + base);
ret = esdhc_writeb_fixup(host, reg, val, value);
iowrite32be(ret, host->ioaddr + base);
}
staticvoid esdhc_le_writeb(struct sdhci_host *host, u8 val, int reg)
{ int base = reg & ~0x3;
u32 value;
u32 ret;
value = ioread32(host->ioaddr + base);
ret = esdhc_writeb_fixup(host, reg, val, value);
iowrite32(ret, host->ioaddr + base);
}
/* * For Abort or Suspend after Stop at Block Gap, ignore the ADMA * error(IRQSTAT[ADMAE]) if both Transfer Complete(IRQSTAT[TC]) * and Block Gap Event(IRQSTAT[BGE]) are also set. * For Continue, apply soft reset for data(SYSCTL[RSTD]); * and re-issue the entire read transaction from beginning.
*/ staticvoid esdhc_of_adma_workaround(struct sdhci_host *host, u32 intmask)
{ struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); struct sdhci_esdhc *esdhc = sdhci_pltfm_priv(pltfm_host); bool applicable;
dma_addr_t dmastart;
dma_addr_t dmanow;
/* * IPGEN/HCKEN/PEREN bits exist on eSDHC whose vendor version * is 2.2 or lower.
*/ if (esdhc->vendor_ver <= VENDOR_V_22)
clk_en |= (ESDHC_CLOCK_IPGEN | ESDHC_CLOCK_HCKEN |
ESDHC_CLOCK_PEREN);
val = sdhci_readl(host, ESDHC_SYSTEM_CONTROL);
if (enable)
val |= clk_en; else
val &= ~clk_en;
sdhci_writel(host, val, ESDHC_SYSTEM_CONTROL);
/* * Wait max 20 ms. If vendor version is 2.2 or lower, do not * wait clock stable bit which does not exist.
*/
timeout = ktime_add_ms(ktime_get(), 20); while (esdhc->vendor_ver > VENDOR_V_22) { bool timedout = ktime_after(ktime_get(), timeout);
if (sdhci_readl(host, ESDHC_PRSSTAT) & ESDHC_CLOCK_STABLE) break; if (timedout) {
pr_err("%s: Internal clock never stabilised.\n",
mmc_hostname(host->mmc)); break;
}
usleep_range(10, 20);
}
}
/* * Wait max 20 ms. If vendor version is 2.2 or lower, do not * wait clock stable bit which does not exist.
*/
timeout = ktime_add_ms(ktime_get(), 20); while (esdhc->vendor_ver > VENDOR_V_22) { bool timedout = ktime_after(ktime_get(), timeout);
if (sdhci_readl(host, ESDHC_PRSSTAT) & ESDHC_CLOCK_STABLE) break; if (timedout) {
pr_err("%s: Internal clock never stabilised.\n",
mmc_hostname(host->mmc)); break;
}
usleep_range(10, 20);
}
/* * Add delay to make sure all the DMA transfers are finished * for quirk.
*/ if (esdhc->quirk_delay_before_data_reset &&
(mask & SDHCI_RESET_DATA) &&
(host->flags & SDHCI_REQ_USE_DMA))
mdelay(5);
/* * Save bus-width for eSDHC whose vendor version is 2.2 * or lower for data reset.
*/ if ((mask & SDHCI_RESET_DATA) &&
(esdhc->vendor_ver <= VENDOR_V_22)) {
val = sdhci_readl(host, ESDHC_PROCTL);
bus_width = val & ESDHC_CTRL_BUSWIDTH_MASK;
}
sdhci_reset(host, mask);
/* * Restore bus-width setting and interrupt registers for eSDHC * whose vendor version is 2.2 or lower for data reset.
*/ if ((mask & SDHCI_RESET_DATA) &&
(esdhc->vendor_ver <= VENDOR_V_22)) {
val = sdhci_readl(host, ESDHC_PROCTL);
val &= ~ESDHC_CTRL_BUSWIDTH_MASK;
val |= bus_width;
sdhci_writel(host, val, ESDHC_PROCTL);
/* * Some bits have to be cleaned manually for eSDHC whose spec * version is higher than 3.0 for all reset.
*/ if ((mask & SDHCI_RESET_ALL) &&
(esdhc->spec_ver >= SDHCI_SPEC_300)) {
val = sdhci_readl(host, ESDHC_TBCTL);
val &= ~ESDHC_TB_EN;
sdhci_writel(host, val, ESDHC_TBCTL);
/* * Initialize eSDHC_DLLCFG1[DLL_PD_PULSE_STRETCH_SEL] to * 0 for quirk.
*/ if (esdhc->quirk_unreliable_pulse_detection) {
val = sdhci_readl(host, ESDHC_DLLCFG1);
val &= ~ESDHC_DLL_PD_PULSE_STRETCH_SEL;
sdhci_writel(host, val, ESDHC_DLLCFG1);
}
}
}
/* The SCFG, Supplemental Configuration Unit, provides SoC specific * configuration and status registers for the device. There is a * SDHC IO VSEL control register on SCFG for some platforms. It's * used to support SDHC IO voltage switching.
*/ staticconststruct of_device_id scfg_device_ids[] = {
{ .compatible = "fsl,t1040-scfg", },
{ .compatible = "fsl,ls1012a-scfg", },
{ .compatible = "fsl,ls1046a-scfg", },
{}
};
/* Program TBPTR[TB_WNDW_END_PTR] and TBPTR[TB_WNDW_START_PTR] */
val = ((u32)window_start << ESDHC_WNDW_STRT_PTR_SHIFT) &
ESDHC_WNDW_STRT_PTR_MASK;
val |= window_end & ESDHC_WNDW_END_PTR_MASK;
sdhci_writel(host, val, ESDHC_TBPTR);
/* Program the software tuning mode by setting TBCTL[TB_MODE]=2'h3 */
val = sdhci_readl(host, ESDHC_TBCTL);
val &= ~ESDHC_TB_MODE_MASK;
val |= ESDHC_TB_MODE_SW;
sdhci_writel(host, val, ESDHC_TBCTL);
/* For tuning mode, the sd clock divisor value * must be larger than 3 according to reference manual.
*/
clk = esdhc->peripheral_clock / 3; if (host->clock > clk)
esdhc_of_set_clock(host, clk);
esdhc_tuning_block_enable(host, true);
/* * The eSDHC controller takes the data timeout value into account * during tuning. If the SD card is too slow sending the response, the * timer will expire and a "Buffer Read Ready" interrupt without data * is triggered. This leads to tuning errors. * * Just set the timeout to the maximum value because the core will * already take care of it in sdhci_send_tuning().
*/
sdhci_writeb(host, 0xe, SDHCI_TIMEOUT_CONTROL);
hs400_tuning = host->flags & SDHCI_HS400_TUNING;
do { if (esdhc->quirk_limited_clk_division &&
hs400_tuning)
esdhc_of_set_clock(host, host->clock);
/* Do HW tuning */
val = sdhci_readl(host, ESDHC_TBCTL);
val &= ~ESDHC_TB_MODE_MASK;
val |= ESDHC_TB_MODE_3;
sdhci_writel(host, val, ESDHC_TBCTL);
ret = sdhci_execute_tuning(mmc, opcode); if (ret) break;
/* For type2 affected platforms of the tuning erratum, * tuning may succeed although eSDHC might not have * tuned properly. Need to check tuning window.
*/ if (esdhc->quirk_tuning_erratum_type2 &&
!host->tuning_err) {
esdhc_tuning_window_ptr(host, &window_start,
&window_end); if (abs(window_start - window_end) >
(4 * esdhc->div_ratio + 2))
host->tuning_err = -EAGAIN;
}
/* If HW tuning fails and triggers erratum, * try workaround.
*/
ret = host->tuning_err; if (ret == -EAGAIN &&
(esdhc->quirk_tuning_erratum_type1 ||
esdhc->quirk_tuning_erratum_type2)) { /* Recover HS400 tuning flag */ if (hs400_tuning)
host->flags |= SDHCI_HS400_TUNING;
pr_info("%s: Hold on to use fixed sampling clock. Try SW tuning!\n",
mmc_hostname(mmc)); /* Do SW tuning */
esdhc_prepare_sw_tuning(host, &window_start,
&window_end);
ret = esdhc_execute_sw_tuning(mmc, opcode,
window_start,
window_end); if (ret) break;
/* Retry both HW/SW tuning with reduced clock. */
ret = host->tuning_err; if (ret == -EAGAIN && retries) { /* Recover HS400 tuning flag */ if (hs400_tuning)
host->flags |= SDHCI_HS400_TUNING;
clk = host->max_clk / (esdhc->div_ratio + 1);
esdhc_of_set_clock(host, clk);
pr_info("%s: Hold on to use fixed sampling clock. Try tuning with reduced clock!\n",
mmc_hostname(mmc));
} else { break;
}
} else { break;
}
} while (retries--);
if (ret) {
esdhc_tuning_block_enable(host, false);
} elseif (hs400_tuning) {
val = sdhci_readl(host, ESDHC_SDTIMNGCTL);
val |= ESDHC_FLW_CTL_BG;
sdhci_writel(host, val, ESDHC_SDTIMNGCTL);
}
/* * There are specific registers setting for HS400 mode. * Clean all of them if controller is in HS400 mode to * exit HS400 mode before re-setting any speed mode.
*/
val = sdhci_readl(host, ESDHC_TBCTL); if (val & ESDHC_HS400_MODE) {
val = sdhci_readl(host, ESDHC_SDTIMNGCTL);
val &= ~ESDHC_FLW_CTL_BG;
sdhci_writel(host, val, ESDHC_SDTIMNGCTL);
val = sdhci_readl(host, ESDHC_SDCLKCTL);
val &= ~ESDHC_CMD_CLK_CTL;
sdhci_writel(host, val, ESDHC_SDCLKCTL);
esdhc_clock_enable(host, false);
val = sdhci_readl(host, ESDHC_TBCTL);
val &= ~ESDHC_HS400_MODE;
sdhci_writel(host, val, ESDHC_TBCTL);
esdhc_clock_enable(host, true);
val = sdhci_readl(host, ESDHC_DLLCFG0);
val &= ~(ESDHC_DLL_ENABLE | ESDHC_DLL_FREQ_SEL);
sdhci_writel(host, val, ESDHC_DLLCFG0);
val = sdhci_readl(host, ESDHC_TBCTL);
val &= ~ESDHC_HS400_WNDW_ADJUST;
sdhci_writel(host, val, ESDHC_TBCTL);
esdhc_tuning_block_enable(host, false);
}
if (timing == MMC_TIMING_MMC_HS400)
esdhc_tuning_block_enable(host, true); else
sdhci_set_uhs_signaling(host, timing);
}
clk = of_clk_get(np, 0); if (!IS_ERR(clk)) { /* * esdhc->peripheral_clock would be assigned with a value * which is eSDHC base clock when use periperal clock. * For some platforms, the clock value got by common clk * API is peripheral clock while the eSDHC base clock is * 1/2 peripheral clock.
*/ if (of_device_is_compatible(np, "fsl,ls1046a-esdhc") ||
of_device_is_compatible(np, "fsl,ls1028a-esdhc") ||
of_device_is_compatible(np, "fsl,ls1088a-esdhc"))
esdhc->peripheral_clock = clk_get_rate(clk) / 2; else
esdhc->peripheral_clock = clk_get_rate(clk);
clk_put(clk);
}
esdhc_clock_enable(host, false);
val = sdhci_readl(host, ESDHC_DMA_SYSCTL); /* * This bit is not able to be reset by SDHCI_RESET_ALL. Need to * initialize it as 1 or 0 once, to override the different value * which may be configured in bootloader.
*/ if (esdhc->peripheral_clock)
val |= ESDHC_PERIPHERAL_CLK_SEL; else
val &= ~ESDHC_PERIPHERAL_CLK_SEL;
sdhci_writel(host, val, ESDHC_DMA_SYSCTL);
esdhc_clock_enable(host, true);
}
if (of_device_is_compatible(np, "fsl,ls1021a-esdhc"))
host->quirks |= SDHCI_QUIRK_BROKEN_TIMEOUT_VAL;
esdhc->quirk_ignore_data_inhibit = false; if (of_device_is_compatible(np, "fsl,p2020-esdhc")) { /* * Freescale messed up with P2020 as it has a non-standard * host control register
*/
host->quirks2 |= SDHCI_QUIRK2_BROKEN_HOST_CONTROL;
esdhc->quirk_ignore_data_inhibit = true;
}
/* call to generic mmc_of_parse to support additional capabilities */
ret = mmc_of_parse(host->mmc); if (ret) return ret;
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.