162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * Freescale eSDHC controller driver.
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci * Copyright (c) 2007, 2010, 2012 Freescale Semiconductor, Inc.
662306a36Sopenharmony_ci * Copyright (c) 2009 MontaVista Software, Inc.
762306a36Sopenharmony_ci * Copyright 2020 NXP
862306a36Sopenharmony_ci *
962306a36Sopenharmony_ci * Authors: Xiaobo Xie <X.Xie@freescale.com>
1062306a36Sopenharmony_ci *	    Anton Vorontsov <avorontsov@ru.mvista.com>
1162306a36Sopenharmony_ci */
1262306a36Sopenharmony_ci
1362306a36Sopenharmony_ci#include <linux/err.h>
1462306a36Sopenharmony_ci#include <linux/io.h>
1562306a36Sopenharmony_ci#include <linux/of.h>
1662306a36Sopenharmony_ci#include <linux/of_address.h>
1762306a36Sopenharmony_ci#include <linux/delay.h>
1862306a36Sopenharmony_ci#include <linux/module.h>
1962306a36Sopenharmony_ci#include <linux/sys_soc.h>
2062306a36Sopenharmony_ci#include <linux/clk.h>
2162306a36Sopenharmony_ci#include <linux/ktime.h>
2262306a36Sopenharmony_ci#include <linux/dma-mapping.h>
2362306a36Sopenharmony_ci#include <linux/iopoll.h>
2462306a36Sopenharmony_ci#include <linux/mmc/host.h>
2562306a36Sopenharmony_ci#include <linux/mmc/mmc.h>
2662306a36Sopenharmony_ci#include "sdhci-pltfm.h"
2762306a36Sopenharmony_ci#include "sdhci-esdhc.h"
2862306a36Sopenharmony_ci
2962306a36Sopenharmony_ci#define VENDOR_V_22	0x12
3062306a36Sopenharmony_ci#define VENDOR_V_23	0x13
3162306a36Sopenharmony_ci
3262306a36Sopenharmony_ci#define MMC_TIMING_NUM (MMC_TIMING_MMC_HS400 + 1)
3362306a36Sopenharmony_ci
3462306a36Sopenharmony_cistruct esdhc_clk_fixup {
3562306a36Sopenharmony_ci	const unsigned int sd_dflt_max_clk;
3662306a36Sopenharmony_ci	const unsigned int max_clk[MMC_TIMING_NUM];
3762306a36Sopenharmony_ci};
3862306a36Sopenharmony_ci
3962306a36Sopenharmony_cistatic const struct esdhc_clk_fixup ls1021a_esdhc_clk = {
4062306a36Sopenharmony_ci	.sd_dflt_max_clk = 25000000,
4162306a36Sopenharmony_ci	.max_clk[MMC_TIMING_MMC_HS] = 46500000,
4262306a36Sopenharmony_ci	.max_clk[MMC_TIMING_SD_HS] = 46500000,
4362306a36Sopenharmony_ci};
4462306a36Sopenharmony_ci
4562306a36Sopenharmony_cistatic const struct esdhc_clk_fixup ls1043a_esdhc_clk = {
4662306a36Sopenharmony_ci	.sd_dflt_max_clk = 25000000,
4762306a36Sopenharmony_ci	.max_clk[MMC_TIMING_UHS_SDR104] = 116700000,
4862306a36Sopenharmony_ci	.max_clk[MMC_TIMING_MMC_HS200] = 116700000,
4962306a36Sopenharmony_ci};
5062306a36Sopenharmony_ci
5162306a36Sopenharmony_cistatic const struct esdhc_clk_fixup ls1046a_esdhc_clk = {
5262306a36Sopenharmony_ci	.sd_dflt_max_clk = 25000000,
5362306a36Sopenharmony_ci	.max_clk[MMC_TIMING_UHS_SDR104] = 167000000,
5462306a36Sopenharmony_ci	.max_clk[MMC_TIMING_MMC_HS200] = 167000000,
5562306a36Sopenharmony_ci};
5662306a36Sopenharmony_ci
5762306a36Sopenharmony_cistatic const struct esdhc_clk_fixup ls1012a_esdhc_clk = {
5862306a36Sopenharmony_ci	.sd_dflt_max_clk = 25000000,
5962306a36Sopenharmony_ci	.max_clk[MMC_TIMING_UHS_SDR104] = 125000000,
6062306a36Sopenharmony_ci	.max_clk[MMC_TIMING_MMC_HS200] = 125000000,
6162306a36Sopenharmony_ci};
6262306a36Sopenharmony_ci
6362306a36Sopenharmony_cistatic const struct esdhc_clk_fixup p1010_esdhc_clk = {
6462306a36Sopenharmony_ci	.sd_dflt_max_clk = 20000000,
6562306a36Sopenharmony_ci	.max_clk[MMC_TIMING_LEGACY] = 20000000,
6662306a36Sopenharmony_ci	.max_clk[MMC_TIMING_MMC_HS] = 42000000,
6762306a36Sopenharmony_ci	.max_clk[MMC_TIMING_SD_HS] = 40000000,
6862306a36Sopenharmony_ci};
6962306a36Sopenharmony_ci
7062306a36Sopenharmony_cistatic const struct of_device_id sdhci_esdhc_of_match[] = {
7162306a36Sopenharmony_ci	{ .compatible = "fsl,ls1021a-esdhc", .data = &ls1021a_esdhc_clk},
7262306a36Sopenharmony_ci	{ .compatible = "fsl,ls1043a-esdhc", .data = &ls1043a_esdhc_clk},
7362306a36Sopenharmony_ci	{ .compatible = "fsl,ls1046a-esdhc", .data = &ls1046a_esdhc_clk},
7462306a36Sopenharmony_ci	{ .compatible = "fsl,ls1012a-esdhc", .data = &ls1012a_esdhc_clk},
7562306a36Sopenharmony_ci	{ .compatible = "fsl,p1010-esdhc",   .data = &p1010_esdhc_clk},
7662306a36Sopenharmony_ci	{ .compatible = "fsl,mpc8379-esdhc" },
7762306a36Sopenharmony_ci	{ .compatible = "fsl,mpc8536-esdhc" },
7862306a36Sopenharmony_ci	{ .compatible = "fsl,esdhc" },
7962306a36Sopenharmony_ci	{ }
8062306a36Sopenharmony_ci};
8162306a36Sopenharmony_ciMODULE_DEVICE_TABLE(of, sdhci_esdhc_of_match);
8262306a36Sopenharmony_ci
8362306a36Sopenharmony_cistruct sdhci_esdhc {
8462306a36Sopenharmony_ci	u8 vendor_ver;
8562306a36Sopenharmony_ci	u8 spec_ver;
8662306a36Sopenharmony_ci	bool quirk_incorrect_hostver;
8762306a36Sopenharmony_ci	bool quirk_limited_clk_division;
8862306a36Sopenharmony_ci	bool quirk_unreliable_pulse_detection;
8962306a36Sopenharmony_ci	bool quirk_tuning_erratum_type1;
9062306a36Sopenharmony_ci	bool quirk_tuning_erratum_type2;
9162306a36Sopenharmony_ci	bool quirk_ignore_data_inhibit;
9262306a36Sopenharmony_ci	bool quirk_delay_before_data_reset;
9362306a36Sopenharmony_ci	bool quirk_trans_complete_erratum;
9462306a36Sopenharmony_ci	bool in_sw_tuning;
9562306a36Sopenharmony_ci	unsigned int peripheral_clock;
9662306a36Sopenharmony_ci	const struct esdhc_clk_fixup *clk_fixup;
9762306a36Sopenharmony_ci	u32 div_ratio;
9862306a36Sopenharmony_ci};
9962306a36Sopenharmony_ci
10062306a36Sopenharmony_ci/**
10162306a36Sopenharmony_ci * esdhc_readl_fixup - Fixup the value read from incompatible eSDHC register
10262306a36Sopenharmony_ci *		       to make it compatible with SD spec.
10362306a36Sopenharmony_ci *
10462306a36Sopenharmony_ci * @host: pointer to sdhci_host
10562306a36Sopenharmony_ci * @spec_reg: SD spec register address
10662306a36Sopenharmony_ci * @value: 32bit eSDHC register value on spec_reg address
10762306a36Sopenharmony_ci *
10862306a36Sopenharmony_ci * In SD spec, there are 8/16/32/64 bits registers, while all of eSDHC
10962306a36Sopenharmony_ci * registers are 32 bits. There are differences in register size, register
11062306a36Sopenharmony_ci * address, register function, bit position and function between eSDHC spec
11162306a36Sopenharmony_ci * and SD spec.
11262306a36Sopenharmony_ci *
11362306a36Sopenharmony_ci * Return a fixed up register value
11462306a36Sopenharmony_ci */
11562306a36Sopenharmony_cistatic u32 esdhc_readl_fixup(struct sdhci_host *host,
11662306a36Sopenharmony_ci				     int spec_reg, u32 value)
11762306a36Sopenharmony_ci{
11862306a36Sopenharmony_ci	struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
11962306a36Sopenharmony_ci	struct sdhci_esdhc *esdhc = sdhci_pltfm_priv(pltfm_host);
12062306a36Sopenharmony_ci	u32 ret;
12162306a36Sopenharmony_ci
12262306a36Sopenharmony_ci	/*
12362306a36Sopenharmony_ci	 * The bit of ADMA flag in eSDHC is not compatible with standard
12462306a36Sopenharmony_ci	 * SDHC register, so set fake flag SDHCI_CAN_DO_ADMA2 when ADMA is
12562306a36Sopenharmony_ci	 * supported by eSDHC.
12662306a36Sopenharmony_ci	 * And for many FSL eSDHC controller, the reset value of field
12762306a36Sopenharmony_ci	 * SDHCI_CAN_DO_ADMA1 is 1, but some of them can't support ADMA,
12862306a36Sopenharmony_ci	 * only these vendor version is greater than 2.2/0x12 support ADMA.
12962306a36Sopenharmony_ci	 */
13062306a36Sopenharmony_ci	if ((spec_reg == SDHCI_CAPABILITIES) && (value & SDHCI_CAN_DO_ADMA1)) {
13162306a36Sopenharmony_ci		if (esdhc->vendor_ver > VENDOR_V_22) {
13262306a36Sopenharmony_ci			ret = value | SDHCI_CAN_DO_ADMA2;
13362306a36Sopenharmony_ci			return ret;
13462306a36Sopenharmony_ci		}
13562306a36Sopenharmony_ci	}
13662306a36Sopenharmony_ci
13762306a36Sopenharmony_ci	/*
13862306a36Sopenharmony_ci	 * The DAT[3:0] line signal levels and the CMD line signal level are
13962306a36Sopenharmony_ci	 * not compatible with standard SDHC register. The line signal levels
14062306a36Sopenharmony_ci	 * DAT[7:0] are at bits 31:24 and the command line signal level is at
14162306a36Sopenharmony_ci	 * bit 23. All other bits are the same as in the standard SDHC
14262306a36Sopenharmony_ci	 * register.
14362306a36Sopenharmony_ci	 */
14462306a36Sopenharmony_ci	if (spec_reg == SDHCI_PRESENT_STATE) {
14562306a36Sopenharmony_ci		ret = value & 0x000fffff;
14662306a36Sopenharmony_ci		ret |= (value >> 4) & SDHCI_DATA_LVL_MASK;
14762306a36Sopenharmony_ci		ret |= (value << 1) & SDHCI_CMD_LVL;
14862306a36Sopenharmony_ci
14962306a36Sopenharmony_ci		/*
15062306a36Sopenharmony_ci		 * Some controllers have unreliable Data Line Active
15162306a36Sopenharmony_ci		 * bit for commands with busy signal. This affects
15262306a36Sopenharmony_ci		 * Command Inhibit (data) bit. Just ignore it since
15362306a36Sopenharmony_ci		 * MMC core driver has already polled card status
15462306a36Sopenharmony_ci		 * with CMD13 after any command with busy siganl.
15562306a36Sopenharmony_ci		 */
15662306a36Sopenharmony_ci		if (esdhc->quirk_ignore_data_inhibit)
15762306a36Sopenharmony_ci			ret &= ~SDHCI_DATA_INHIBIT;
15862306a36Sopenharmony_ci		return ret;
15962306a36Sopenharmony_ci	}
16062306a36Sopenharmony_ci
16162306a36Sopenharmony_ci	/*
16262306a36Sopenharmony_ci	 * DTS properties of mmc host are used to enable each speed mode
16362306a36Sopenharmony_ci	 * according to soc and board capability. So clean up
16462306a36Sopenharmony_ci	 * SDR50/SDR104/DDR50 support bits here.
16562306a36Sopenharmony_ci	 */
16662306a36Sopenharmony_ci	if (spec_reg == SDHCI_CAPABILITIES_1) {
16762306a36Sopenharmony_ci		ret = value & ~(SDHCI_SUPPORT_SDR50 | SDHCI_SUPPORT_SDR104 |
16862306a36Sopenharmony_ci				SDHCI_SUPPORT_DDR50);
16962306a36Sopenharmony_ci		return ret;
17062306a36Sopenharmony_ci	}
17162306a36Sopenharmony_ci
17262306a36Sopenharmony_ci	ret = value;
17362306a36Sopenharmony_ci	return ret;
17462306a36Sopenharmony_ci}
17562306a36Sopenharmony_ci
17662306a36Sopenharmony_cistatic u16 esdhc_readw_fixup(struct sdhci_host *host,
17762306a36Sopenharmony_ci				     int spec_reg, u32 value)
17862306a36Sopenharmony_ci{
17962306a36Sopenharmony_ci	struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
18062306a36Sopenharmony_ci	struct sdhci_esdhc *esdhc = sdhci_pltfm_priv(pltfm_host);
18162306a36Sopenharmony_ci	u16 ret;
18262306a36Sopenharmony_ci	int shift = (spec_reg & 0x2) * 8;
18362306a36Sopenharmony_ci
18462306a36Sopenharmony_ci	if (spec_reg == SDHCI_TRANSFER_MODE)
18562306a36Sopenharmony_ci		return pltfm_host->xfer_mode_shadow;
18662306a36Sopenharmony_ci
18762306a36Sopenharmony_ci	if (spec_reg == SDHCI_HOST_VERSION)
18862306a36Sopenharmony_ci		ret = value & 0xffff;
18962306a36Sopenharmony_ci	else
19062306a36Sopenharmony_ci		ret = (value >> shift) & 0xffff;
19162306a36Sopenharmony_ci	/* Workaround for T4240-R1.0-R2.0 eSDHC which has incorrect
19262306a36Sopenharmony_ci	 * vendor version and spec version information.
19362306a36Sopenharmony_ci	 */
19462306a36Sopenharmony_ci	if ((spec_reg == SDHCI_HOST_VERSION) &&
19562306a36Sopenharmony_ci	    (esdhc->quirk_incorrect_hostver))
19662306a36Sopenharmony_ci		ret = (VENDOR_V_23 << SDHCI_VENDOR_VER_SHIFT) | SDHCI_SPEC_200;
19762306a36Sopenharmony_ci	return ret;
19862306a36Sopenharmony_ci}
19962306a36Sopenharmony_ci
20062306a36Sopenharmony_cistatic u8 esdhc_readb_fixup(struct sdhci_host *host,
20162306a36Sopenharmony_ci				     int spec_reg, u32 value)
20262306a36Sopenharmony_ci{
20362306a36Sopenharmony_ci	u8 ret;
20462306a36Sopenharmony_ci	u8 dma_bits;
20562306a36Sopenharmony_ci	int shift = (spec_reg & 0x3) * 8;
20662306a36Sopenharmony_ci
20762306a36Sopenharmony_ci	ret = (value >> shift) & 0xff;
20862306a36Sopenharmony_ci
20962306a36Sopenharmony_ci	/*
21062306a36Sopenharmony_ci	 * "DMA select" locates at offset 0x28 in SD specification, but on
21162306a36Sopenharmony_ci	 * P5020 or P3041, it locates at 0x29.
21262306a36Sopenharmony_ci	 */
21362306a36Sopenharmony_ci	if (spec_reg == SDHCI_HOST_CONTROL) {
21462306a36Sopenharmony_ci		/* DMA select is 22,23 bits in Protocol Control Register */
21562306a36Sopenharmony_ci		dma_bits = (value >> 5) & SDHCI_CTRL_DMA_MASK;
21662306a36Sopenharmony_ci		/* fixup the result */
21762306a36Sopenharmony_ci		ret &= ~SDHCI_CTRL_DMA_MASK;
21862306a36Sopenharmony_ci		ret |= dma_bits;
21962306a36Sopenharmony_ci	}
22062306a36Sopenharmony_ci	return ret;
22162306a36Sopenharmony_ci}
22262306a36Sopenharmony_ci
22362306a36Sopenharmony_ci/**
22462306a36Sopenharmony_ci * esdhc_writel_fixup - Fixup the SD spec register value so that it could be
22562306a36Sopenharmony_ci *			written into eSDHC register.
22662306a36Sopenharmony_ci *
22762306a36Sopenharmony_ci * @host: pointer to sdhci_host
22862306a36Sopenharmony_ci * @spec_reg: SD spec register address
22962306a36Sopenharmony_ci * @value: 8/16/32bit SD spec register value that would be written
23062306a36Sopenharmony_ci * @old_value: 32bit eSDHC register value on spec_reg address
23162306a36Sopenharmony_ci *
23262306a36Sopenharmony_ci * In SD spec, there are 8/16/32/64 bits registers, while all of eSDHC
23362306a36Sopenharmony_ci * registers are 32 bits. There are differences in register size, register
23462306a36Sopenharmony_ci * address, register function, bit position and function between eSDHC spec
23562306a36Sopenharmony_ci * and SD spec.
23662306a36Sopenharmony_ci *
23762306a36Sopenharmony_ci * Return a fixed up register value
23862306a36Sopenharmony_ci */
23962306a36Sopenharmony_cistatic u32 esdhc_writel_fixup(struct sdhci_host *host,
24062306a36Sopenharmony_ci				     int spec_reg, u32 value, u32 old_value)
24162306a36Sopenharmony_ci{
24262306a36Sopenharmony_ci	u32 ret;
24362306a36Sopenharmony_ci
24462306a36Sopenharmony_ci	/*
24562306a36Sopenharmony_ci	 * Enabling IRQSTATEN[BGESEN] is just to set IRQSTAT[BGE]
24662306a36Sopenharmony_ci	 * when SYSCTL[RSTD] is set for some special operations.
24762306a36Sopenharmony_ci	 * No any impact on other operation.
24862306a36Sopenharmony_ci	 */
24962306a36Sopenharmony_ci	if (spec_reg == SDHCI_INT_ENABLE)
25062306a36Sopenharmony_ci		ret = value | SDHCI_INT_BLK_GAP;
25162306a36Sopenharmony_ci	else
25262306a36Sopenharmony_ci		ret = value;
25362306a36Sopenharmony_ci
25462306a36Sopenharmony_ci	return ret;
25562306a36Sopenharmony_ci}
25662306a36Sopenharmony_ci
25762306a36Sopenharmony_cistatic u32 esdhc_writew_fixup(struct sdhci_host *host,
25862306a36Sopenharmony_ci				     int spec_reg, u16 value, u32 old_value)
25962306a36Sopenharmony_ci{
26062306a36Sopenharmony_ci	struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
26162306a36Sopenharmony_ci	int shift = (spec_reg & 0x2) * 8;
26262306a36Sopenharmony_ci	u32 ret;
26362306a36Sopenharmony_ci
26462306a36Sopenharmony_ci	switch (spec_reg) {
26562306a36Sopenharmony_ci	case SDHCI_TRANSFER_MODE:
26662306a36Sopenharmony_ci		/*
26762306a36Sopenharmony_ci		 * Postpone this write, we must do it together with a
26862306a36Sopenharmony_ci		 * command write that is down below. Return old value.
26962306a36Sopenharmony_ci		 */
27062306a36Sopenharmony_ci		pltfm_host->xfer_mode_shadow = value;
27162306a36Sopenharmony_ci		return old_value;
27262306a36Sopenharmony_ci	case SDHCI_COMMAND:
27362306a36Sopenharmony_ci		ret = (value << 16) | pltfm_host->xfer_mode_shadow;
27462306a36Sopenharmony_ci		return ret;
27562306a36Sopenharmony_ci	}
27662306a36Sopenharmony_ci
27762306a36Sopenharmony_ci	ret = old_value & (~(0xffff << shift));
27862306a36Sopenharmony_ci	ret |= (value << shift);
27962306a36Sopenharmony_ci
28062306a36Sopenharmony_ci	if (spec_reg == SDHCI_BLOCK_SIZE) {
28162306a36Sopenharmony_ci		/*
28262306a36Sopenharmony_ci		 * Two last DMA bits are reserved, and first one is used for
28362306a36Sopenharmony_ci		 * non-standard blksz of 4096 bytes that we don't support
28462306a36Sopenharmony_ci		 * yet. So clear the DMA boundary bits.
28562306a36Sopenharmony_ci		 */
28662306a36Sopenharmony_ci		ret &= (~SDHCI_MAKE_BLKSZ(0x7, 0));
28762306a36Sopenharmony_ci	}
28862306a36Sopenharmony_ci	return ret;
28962306a36Sopenharmony_ci}
29062306a36Sopenharmony_ci
29162306a36Sopenharmony_cistatic u32 esdhc_writeb_fixup(struct sdhci_host *host,
29262306a36Sopenharmony_ci				     int spec_reg, u8 value, u32 old_value)
29362306a36Sopenharmony_ci{
29462306a36Sopenharmony_ci	u32 ret;
29562306a36Sopenharmony_ci	u32 dma_bits;
29662306a36Sopenharmony_ci	u8 tmp;
29762306a36Sopenharmony_ci	int shift = (spec_reg & 0x3) * 8;
29862306a36Sopenharmony_ci
29962306a36Sopenharmony_ci	/*
30062306a36Sopenharmony_ci	 * eSDHC doesn't have a standard power control register, so we do
30162306a36Sopenharmony_ci	 * nothing here to avoid incorrect operation.
30262306a36Sopenharmony_ci	 */
30362306a36Sopenharmony_ci	if (spec_reg == SDHCI_POWER_CONTROL)
30462306a36Sopenharmony_ci		return old_value;
30562306a36Sopenharmony_ci	/*
30662306a36Sopenharmony_ci	 * "DMA select" location is offset 0x28 in SD specification, but on
30762306a36Sopenharmony_ci	 * P5020 or P3041, it's located at 0x29.
30862306a36Sopenharmony_ci	 */
30962306a36Sopenharmony_ci	if (spec_reg == SDHCI_HOST_CONTROL) {
31062306a36Sopenharmony_ci		/*
31162306a36Sopenharmony_ci		 * If host control register is not standard, exit
31262306a36Sopenharmony_ci		 * this function
31362306a36Sopenharmony_ci		 */
31462306a36Sopenharmony_ci		if (host->quirks2 & SDHCI_QUIRK2_BROKEN_HOST_CONTROL)
31562306a36Sopenharmony_ci			return old_value;
31662306a36Sopenharmony_ci
31762306a36Sopenharmony_ci		/* DMA select is 22,23 bits in Protocol Control Register */
31862306a36Sopenharmony_ci		dma_bits = (value & SDHCI_CTRL_DMA_MASK) << 5;
31962306a36Sopenharmony_ci		ret = (old_value & (~(SDHCI_CTRL_DMA_MASK << 5))) | dma_bits;
32062306a36Sopenharmony_ci		tmp = (value & (~SDHCI_CTRL_DMA_MASK)) |
32162306a36Sopenharmony_ci		      (old_value & SDHCI_CTRL_DMA_MASK);
32262306a36Sopenharmony_ci		ret = (ret & (~0xff)) | tmp;
32362306a36Sopenharmony_ci
32462306a36Sopenharmony_ci		/* Prevent SDHCI core from writing reserved bits (e.g. HISPD) */
32562306a36Sopenharmony_ci		ret &= ~ESDHC_HOST_CONTROL_RES;
32662306a36Sopenharmony_ci		return ret;
32762306a36Sopenharmony_ci	}
32862306a36Sopenharmony_ci
32962306a36Sopenharmony_ci	ret = (old_value & (~(0xff << shift))) | (value << shift);
33062306a36Sopenharmony_ci	return ret;
33162306a36Sopenharmony_ci}
33262306a36Sopenharmony_ci
33362306a36Sopenharmony_cistatic u32 esdhc_be_readl(struct sdhci_host *host, int reg)
33462306a36Sopenharmony_ci{
33562306a36Sopenharmony_ci	u32 ret;
33662306a36Sopenharmony_ci	u32 value;
33762306a36Sopenharmony_ci
33862306a36Sopenharmony_ci	if (reg == SDHCI_CAPABILITIES_1)
33962306a36Sopenharmony_ci		value = ioread32be(host->ioaddr + ESDHC_CAPABILITIES_1);
34062306a36Sopenharmony_ci	else
34162306a36Sopenharmony_ci		value = ioread32be(host->ioaddr + reg);
34262306a36Sopenharmony_ci
34362306a36Sopenharmony_ci	ret = esdhc_readl_fixup(host, reg, value);
34462306a36Sopenharmony_ci
34562306a36Sopenharmony_ci	return ret;
34662306a36Sopenharmony_ci}
34762306a36Sopenharmony_ci
34862306a36Sopenharmony_cistatic u32 esdhc_le_readl(struct sdhci_host *host, int reg)
34962306a36Sopenharmony_ci{
35062306a36Sopenharmony_ci	u32 ret;
35162306a36Sopenharmony_ci	u32 value;
35262306a36Sopenharmony_ci
35362306a36Sopenharmony_ci	if (reg == SDHCI_CAPABILITIES_1)
35462306a36Sopenharmony_ci		value = ioread32(host->ioaddr + ESDHC_CAPABILITIES_1);
35562306a36Sopenharmony_ci	else
35662306a36Sopenharmony_ci		value = ioread32(host->ioaddr + reg);
35762306a36Sopenharmony_ci
35862306a36Sopenharmony_ci	ret = esdhc_readl_fixup(host, reg, value);
35962306a36Sopenharmony_ci
36062306a36Sopenharmony_ci	return ret;
36162306a36Sopenharmony_ci}
36262306a36Sopenharmony_ci
36362306a36Sopenharmony_cistatic u16 esdhc_be_readw(struct sdhci_host *host, int reg)
36462306a36Sopenharmony_ci{
36562306a36Sopenharmony_ci	u16 ret;
36662306a36Sopenharmony_ci	u32 value;
36762306a36Sopenharmony_ci	int base = reg & ~0x3;
36862306a36Sopenharmony_ci
36962306a36Sopenharmony_ci	value = ioread32be(host->ioaddr + base);
37062306a36Sopenharmony_ci	ret = esdhc_readw_fixup(host, reg, value);
37162306a36Sopenharmony_ci	return ret;
37262306a36Sopenharmony_ci}
37362306a36Sopenharmony_ci
37462306a36Sopenharmony_cistatic u16 esdhc_le_readw(struct sdhci_host *host, int reg)
37562306a36Sopenharmony_ci{
37662306a36Sopenharmony_ci	u16 ret;
37762306a36Sopenharmony_ci	u32 value;
37862306a36Sopenharmony_ci	int base = reg & ~0x3;
37962306a36Sopenharmony_ci
38062306a36Sopenharmony_ci	value = ioread32(host->ioaddr + base);
38162306a36Sopenharmony_ci	ret = esdhc_readw_fixup(host, reg, value);
38262306a36Sopenharmony_ci	return ret;
38362306a36Sopenharmony_ci}
38462306a36Sopenharmony_ci
38562306a36Sopenharmony_cistatic u8 esdhc_be_readb(struct sdhci_host *host, int reg)
38662306a36Sopenharmony_ci{
38762306a36Sopenharmony_ci	u8 ret;
38862306a36Sopenharmony_ci	u32 value;
38962306a36Sopenharmony_ci	int base = reg & ~0x3;
39062306a36Sopenharmony_ci
39162306a36Sopenharmony_ci	value = ioread32be(host->ioaddr + base);
39262306a36Sopenharmony_ci	ret = esdhc_readb_fixup(host, reg, value);
39362306a36Sopenharmony_ci	return ret;
39462306a36Sopenharmony_ci}
39562306a36Sopenharmony_ci
39662306a36Sopenharmony_cistatic u8 esdhc_le_readb(struct sdhci_host *host, int reg)
39762306a36Sopenharmony_ci{
39862306a36Sopenharmony_ci	u8 ret;
39962306a36Sopenharmony_ci	u32 value;
40062306a36Sopenharmony_ci	int base = reg & ~0x3;
40162306a36Sopenharmony_ci
40262306a36Sopenharmony_ci	value = ioread32(host->ioaddr + base);
40362306a36Sopenharmony_ci	ret = esdhc_readb_fixup(host, reg, value);
40462306a36Sopenharmony_ci	return ret;
40562306a36Sopenharmony_ci}
40662306a36Sopenharmony_ci
40762306a36Sopenharmony_cistatic void esdhc_be_writel(struct sdhci_host *host, u32 val, int reg)
40862306a36Sopenharmony_ci{
40962306a36Sopenharmony_ci	u32 value;
41062306a36Sopenharmony_ci
41162306a36Sopenharmony_ci	value = esdhc_writel_fixup(host, reg, val, 0);
41262306a36Sopenharmony_ci	iowrite32be(value, host->ioaddr + reg);
41362306a36Sopenharmony_ci}
41462306a36Sopenharmony_ci
41562306a36Sopenharmony_cistatic void esdhc_le_writel(struct sdhci_host *host, u32 val, int reg)
41662306a36Sopenharmony_ci{
41762306a36Sopenharmony_ci	u32 value;
41862306a36Sopenharmony_ci
41962306a36Sopenharmony_ci	value = esdhc_writel_fixup(host, reg, val, 0);
42062306a36Sopenharmony_ci	iowrite32(value, host->ioaddr + reg);
42162306a36Sopenharmony_ci}
42262306a36Sopenharmony_ci
42362306a36Sopenharmony_cistatic void esdhc_be_writew(struct sdhci_host *host, u16 val, int reg)
42462306a36Sopenharmony_ci{
42562306a36Sopenharmony_ci	struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
42662306a36Sopenharmony_ci	struct sdhci_esdhc *esdhc = sdhci_pltfm_priv(pltfm_host);
42762306a36Sopenharmony_ci	int base = reg & ~0x3;
42862306a36Sopenharmony_ci	u32 value;
42962306a36Sopenharmony_ci	u32 ret;
43062306a36Sopenharmony_ci
43162306a36Sopenharmony_ci	value = ioread32be(host->ioaddr + base);
43262306a36Sopenharmony_ci	ret = esdhc_writew_fixup(host, reg, val, value);
43362306a36Sopenharmony_ci	if (reg != SDHCI_TRANSFER_MODE)
43462306a36Sopenharmony_ci		iowrite32be(ret, host->ioaddr + base);
43562306a36Sopenharmony_ci
43662306a36Sopenharmony_ci	/* Starting SW tuning requires ESDHC_SMPCLKSEL to be set
43762306a36Sopenharmony_ci	 * 1us later after ESDHC_EXTN is set.
43862306a36Sopenharmony_ci	 */
43962306a36Sopenharmony_ci	if (base == ESDHC_SYSTEM_CONTROL_2) {
44062306a36Sopenharmony_ci		if (!(value & ESDHC_EXTN) && (ret & ESDHC_EXTN) &&
44162306a36Sopenharmony_ci		    esdhc->in_sw_tuning) {
44262306a36Sopenharmony_ci			udelay(1);
44362306a36Sopenharmony_ci			ret |= ESDHC_SMPCLKSEL;
44462306a36Sopenharmony_ci			iowrite32be(ret, host->ioaddr + base);
44562306a36Sopenharmony_ci		}
44662306a36Sopenharmony_ci	}
44762306a36Sopenharmony_ci}
44862306a36Sopenharmony_ci
44962306a36Sopenharmony_cistatic void esdhc_le_writew(struct sdhci_host *host, u16 val, int reg)
45062306a36Sopenharmony_ci{
45162306a36Sopenharmony_ci	struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
45262306a36Sopenharmony_ci	struct sdhci_esdhc *esdhc = sdhci_pltfm_priv(pltfm_host);
45362306a36Sopenharmony_ci	int base = reg & ~0x3;
45462306a36Sopenharmony_ci	u32 value;
45562306a36Sopenharmony_ci	u32 ret;
45662306a36Sopenharmony_ci
45762306a36Sopenharmony_ci	value = ioread32(host->ioaddr + base);
45862306a36Sopenharmony_ci	ret = esdhc_writew_fixup(host, reg, val, value);
45962306a36Sopenharmony_ci	if (reg != SDHCI_TRANSFER_MODE)
46062306a36Sopenharmony_ci		iowrite32(ret, host->ioaddr + base);
46162306a36Sopenharmony_ci
46262306a36Sopenharmony_ci	/* Starting SW tuning requires ESDHC_SMPCLKSEL to be set
46362306a36Sopenharmony_ci	 * 1us later after ESDHC_EXTN is set.
46462306a36Sopenharmony_ci	 */
46562306a36Sopenharmony_ci	if (base == ESDHC_SYSTEM_CONTROL_2) {
46662306a36Sopenharmony_ci		if (!(value & ESDHC_EXTN) && (ret & ESDHC_EXTN) &&
46762306a36Sopenharmony_ci		    esdhc->in_sw_tuning) {
46862306a36Sopenharmony_ci			udelay(1);
46962306a36Sopenharmony_ci			ret |= ESDHC_SMPCLKSEL;
47062306a36Sopenharmony_ci			iowrite32(ret, host->ioaddr + base);
47162306a36Sopenharmony_ci		}
47262306a36Sopenharmony_ci	}
47362306a36Sopenharmony_ci}
47462306a36Sopenharmony_ci
47562306a36Sopenharmony_cistatic void esdhc_be_writeb(struct sdhci_host *host, u8 val, int reg)
47662306a36Sopenharmony_ci{
47762306a36Sopenharmony_ci	int base = reg & ~0x3;
47862306a36Sopenharmony_ci	u32 value;
47962306a36Sopenharmony_ci	u32 ret;
48062306a36Sopenharmony_ci
48162306a36Sopenharmony_ci	value = ioread32be(host->ioaddr + base);
48262306a36Sopenharmony_ci	ret = esdhc_writeb_fixup(host, reg, val, value);
48362306a36Sopenharmony_ci	iowrite32be(ret, host->ioaddr + base);
48462306a36Sopenharmony_ci}
48562306a36Sopenharmony_ci
48662306a36Sopenharmony_cistatic void esdhc_le_writeb(struct sdhci_host *host, u8 val, int reg)
48762306a36Sopenharmony_ci{
48862306a36Sopenharmony_ci	int base = reg & ~0x3;
48962306a36Sopenharmony_ci	u32 value;
49062306a36Sopenharmony_ci	u32 ret;
49162306a36Sopenharmony_ci
49262306a36Sopenharmony_ci	value = ioread32(host->ioaddr + base);
49362306a36Sopenharmony_ci	ret = esdhc_writeb_fixup(host, reg, val, value);
49462306a36Sopenharmony_ci	iowrite32(ret, host->ioaddr + base);
49562306a36Sopenharmony_ci}
49662306a36Sopenharmony_ci
49762306a36Sopenharmony_ci/*
49862306a36Sopenharmony_ci * For Abort or Suspend after Stop at Block Gap, ignore the ADMA
49962306a36Sopenharmony_ci * error(IRQSTAT[ADMAE]) if both Transfer Complete(IRQSTAT[TC])
50062306a36Sopenharmony_ci * and Block Gap Event(IRQSTAT[BGE]) are also set.
50162306a36Sopenharmony_ci * For Continue, apply soft reset for data(SYSCTL[RSTD]);
50262306a36Sopenharmony_ci * and re-issue the entire read transaction from beginning.
50362306a36Sopenharmony_ci */
50462306a36Sopenharmony_cistatic void esdhc_of_adma_workaround(struct sdhci_host *host, u32 intmask)
50562306a36Sopenharmony_ci{
50662306a36Sopenharmony_ci	struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
50762306a36Sopenharmony_ci	struct sdhci_esdhc *esdhc = sdhci_pltfm_priv(pltfm_host);
50862306a36Sopenharmony_ci	bool applicable;
50962306a36Sopenharmony_ci	dma_addr_t dmastart;
51062306a36Sopenharmony_ci	dma_addr_t dmanow;
51162306a36Sopenharmony_ci
51262306a36Sopenharmony_ci	applicable = (intmask & SDHCI_INT_DATA_END) &&
51362306a36Sopenharmony_ci		     (intmask & SDHCI_INT_BLK_GAP) &&
51462306a36Sopenharmony_ci		     (esdhc->vendor_ver == VENDOR_V_23);
51562306a36Sopenharmony_ci	if (!applicable)
51662306a36Sopenharmony_ci		return;
51762306a36Sopenharmony_ci
51862306a36Sopenharmony_ci	host->data->error = 0;
51962306a36Sopenharmony_ci	dmastart = sg_dma_address(host->data->sg);
52062306a36Sopenharmony_ci	dmanow = dmastart + host->data->bytes_xfered;
52162306a36Sopenharmony_ci	/*
52262306a36Sopenharmony_ci	 * Force update to the next DMA block boundary.
52362306a36Sopenharmony_ci	 */
52462306a36Sopenharmony_ci	dmanow = (dmanow & ~(SDHCI_DEFAULT_BOUNDARY_SIZE - 1)) +
52562306a36Sopenharmony_ci		SDHCI_DEFAULT_BOUNDARY_SIZE;
52662306a36Sopenharmony_ci	host->data->bytes_xfered = dmanow - dmastart;
52762306a36Sopenharmony_ci	sdhci_writel(host, dmanow, SDHCI_DMA_ADDRESS);
52862306a36Sopenharmony_ci}
52962306a36Sopenharmony_ci
53062306a36Sopenharmony_cistatic int esdhc_of_enable_dma(struct sdhci_host *host)
53162306a36Sopenharmony_ci{
53262306a36Sopenharmony_ci	int ret;
53362306a36Sopenharmony_ci	u32 value;
53462306a36Sopenharmony_ci	struct device *dev = mmc_dev(host->mmc);
53562306a36Sopenharmony_ci
53662306a36Sopenharmony_ci	if (of_device_is_compatible(dev->of_node, "fsl,ls1043a-esdhc") ||
53762306a36Sopenharmony_ci	    of_device_is_compatible(dev->of_node, "fsl,ls1046a-esdhc")) {
53862306a36Sopenharmony_ci		ret = dma_set_mask_and_coherent(dev, DMA_BIT_MASK(40));
53962306a36Sopenharmony_ci		if (ret)
54062306a36Sopenharmony_ci			return ret;
54162306a36Sopenharmony_ci	}
54262306a36Sopenharmony_ci
54362306a36Sopenharmony_ci	value = sdhci_readl(host, ESDHC_DMA_SYSCTL);
54462306a36Sopenharmony_ci
54562306a36Sopenharmony_ci	if (of_dma_is_coherent(dev->of_node))
54662306a36Sopenharmony_ci		value |= ESDHC_DMA_SNOOP;
54762306a36Sopenharmony_ci	else
54862306a36Sopenharmony_ci		value &= ~ESDHC_DMA_SNOOP;
54962306a36Sopenharmony_ci
55062306a36Sopenharmony_ci	sdhci_writel(host, value, ESDHC_DMA_SYSCTL);
55162306a36Sopenharmony_ci	return 0;
55262306a36Sopenharmony_ci}
55362306a36Sopenharmony_ci
55462306a36Sopenharmony_cistatic unsigned int esdhc_of_get_max_clock(struct sdhci_host *host)
55562306a36Sopenharmony_ci{
55662306a36Sopenharmony_ci	struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
55762306a36Sopenharmony_ci	struct sdhci_esdhc *esdhc = sdhci_pltfm_priv(pltfm_host);
55862306a36Sopenharmony_ci
55962306a36Sopenharmony_ci	if (esdhc->peripheral_clock)
56062306a36Sopenharmony_ci		return esdhc->peripheral_clock;
56162306a36Sopenharmony_ci	else
56262306a36Sopenharmony_ci		return pltfm_host->clock;
56362306a36Sopenharmony_ci}
56462306a36Sopenharmony_ci
56562306a36Sopenharmony_cistatic unsigned int esdhc_of_get_min_clock(struct sdhci_host *host)
56662306a36Sopenharmony_ci{
56762306a36Sopenharmony_ci	struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
56862306a36Sopenharmony_ci	struct sdhci_esdhc *esdhc = sdhci_pltfm_priv(pltfm_host);
56962306a36Sopenharmony_ci	unsigned int clock;
57062306a36Sopenharmony_ci
57162306a36Sopenharmony_ci	if (esdhc->peripheral_clock)
57262306a36Sopenharmony_ci		clock = esdhc->peripheral_clock;
57362306a36Sopenharmony_ci	else
57462306a36Sopenharmony_ci		clock = pltfm_host->clock;
57562306a36Sopenharmony_ci	return clock / 256 / 16;
57662306a36Sopenharmony_ci}
57762306a36Sopenharmony_ci
57862306a36Sopenharmony_cistatic void esdhc_clock_enable(struct sdhci_host *host, bool enable)
57962306a36Sopenharmony_ci{
58062306a36Sopenharmony_ci	struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
58162306a36Sopenharmony_ci	struct sdhci_esdhc *esdhc = sdhci_pltfm_priv(pltfm_host);
58262306a36Sopenharmony_ci	ktime_t timeout;
58362306a36Sopenharmony_ci	u32 val, clk_en;
58462306a36Sopenharmony_ci
58562306a36Sopenharmony_ci	clk_en = ESDHC_CLOCK_SDCLKEN;
58662306a36Sopenharmony_ci
58762306a36Sopenharmony_ci	/*
58862306a36Sopenharmony_ci	 * IPGEN/HCKEN/PEREN bits exist on eSDHC whose vendor version
58962306a36Sopenharmony_ci	 * is 2.2 or lower.
59062306a36Sopenharmony_ci	 */
59162306a36Sopenharmony_ci	if (esdhc->vendor_ver <= VENDOR_V_22)
59262306a36Sopenharmony_ci		clk_en |= (ESDHC_CLOCK_IPGEN | ESDHC_CLOCK_HCKEN |
59362306a36Sopenharmony_ci			   ESDHC_CLOCK_PEREN);
59462306a36Sopenharmony_ci
59562306a36Sopenharmony_ci	val = sdhci_readl(host, ESDHC_SYSTEM_CONTROL);
59662306a36Sopenharmony_ci
59762306a36Sopenharmony_ci	if (enable)
59862306a36Sopenharmony_ci		val |= clk_en;
59962306a36Sopenharmony_ci	else
60062306a36Sopenharmony_ci		val &= ~clk_en;
60162306a36Sopenharmony_ci
60262306a36Sopenharmony_ci	sdhci_writel(host, val, ESDHC_SYSTEM_CONTROL);
60362306a36Sopenharmony_ci
60462306a36Sopenharmony_ci	/*
60562306a36Sopenharmony_ci	 * Wait max 20 ms. If vendor version is 2.2 or lower, do not
60662306a36Sopenharmony_ci	 * wait clock stable bit which does not exist.
60762306a36Sopenharmony_ci	 */
60862306a36Sopenharmony_ci	timeout = ktime_add_ms(ktime_get(), 20);
60962306a36Sopenharmony_ci	while (esdhc->vendor_ver > VENDOR_V_22) {
61062306a36Sopenharmony_ci		bool timedout = ktime_after(ktime_get(), timeout);
61162306a36Sopenharmony_ci
61262306a36Sopenharmony_ci		if (sdhci_readl(host, ESDHC_PRSSTAT) & ESDHC_CLOCK_STABLE)
61362306a36Sopenharmony_ci			break;
61462306a36Sopenharmony_ci		if (timedout) {
61562306a36Sopenharmony_ci			pr_err("%s: Internal clock never stabilised.\n",
61662306a36Sopenharmony_ci				mmc_hostname(host->mmc));
61762306a36Sopenharmony_ci			break;
61862306a36Sopenharmony_ci		}
61962306a36Sopenharmony_ci		usleep_range(10, 20);
62062306a36Sopenharmony_ci	}
62162306a36Sopenharmony_ci}
62262306a36Sopenharmony_ci
62362306a36Sopenharmony_cistatic void esdhc_flush_async_fifo(struct sdhci_host *host)
62462306a36Sopenharmony_ci{
62562306a36Sopenharmony_ci	ktime_t timeout;
62662306a36Sopenharmony_ci	u32 val;
62762306a36Sopenharmony_ci
62862306a36Sopenharmony_ci	val = sdhci_readl(host, ESDHC_DMA_SYSCTL);
62962306a36Sopenharmony_ci	val |= ESDHC_FLUSH_ASYNC_FIFO;
63062306a36Sopenharmony_ci	sdhci_writel(host, val, ESDHC_DMA_SYSCTL);
63162306a36Sopenharmony_ci
63262306a36Sopenharmony_ci	/* Wait max 20 ms */
63362306a36Sopenharmony_ci	timeout = ktime_add_ms(ktime_get(), 20);
63462306a36Sopenharmony_ci	while (1) {
63562306a36Sopenharmony_ci		bool timedout = ktime_after(ktime_get(), timeout);
63662306a36Sopenharmony_ci
63762306a36Sopenharmony_ci		if (!(sdhci_readl(host, ESDHC_DMA_SYSCTL) &
63862306a36Sopenharmony_ci		      ESDHC_FLUSH_ASYNC_FIFO))
63962306a36Sopenharmony_ci			break;
64062306a36Sopenharmony_ci		if (timedout) {
64162306a36Sopenharmony_ci			pr_err("%s: flushing asynchronous FIFO timeout.\n",
64262306a36Sopenharmony_ci				mmc_hostname(host->mmc));
64362306a36Sopenharmony_ci			break;
64462306a36Sopenharmony_ci		}
64562306a36Sopenharmony_ci		usleep_range(10, 20);
64662306a36Sopenharmony_ci	}
64762306a36Sopenharmony_ci}
64862306a36Sopenharmony_ci
64962306a36Sopenharmony_cistatic void esdhc_of_set_clock(struct sdhci_host *host, unsigned int clock)
65062306a36Sopenharmony_ci{
65162306a36Sopenharmony_ci	struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
65262306a36Sopenharmony_ci	struct sdhci_esdhc *esdhc = sdhci_pltfm_priv(pltfm_host);
65362306a36Sopenharmony_ci	unsigned int pre_div = 1, div = 1;
65462306a36Sopenharmony_ci	unsigned int clock_fixup = 0;
65562306a36Sopenharmony_ci	ktime_t timeout;
65662306a36Sopenharmony_ci	u32 temp;
65762306a36Sopenharmony_ci
65862306a36Sopenharmony_ci	if (clock == 0) {
65962306a36Sopenharmony_ci		host->mmc->actual_clock = 0;
66062306a36Sopenharmony_ci		esdhc_clock_enable(host, false);
66162306a36Sopenharmony_ci		return;
66262306a36Sopenharmony_ci	}
66362306a36Sopenharmony_ci
66462306a36Sopenharmony_ci	/* Start pre_div at 2 for vendor version < 2.3. */
66562306a36Sopenharmony_ci	if (esdhc->vendor_ver < VENDOR_V_23)
66662306a36Sopenharmony_ci		pre_div = 2;
66762306a36Sopenharmony_ci
66862306a36Sopenharmony_ci	/* Fix clock value. */
66962306a36Sopenharmony_ci	if (host->mmc->card && mmc_card_sd(host->mmc->card) &&
67062306a36Sopenharmony_ci	    esdhc->clk_fixup && host->mmc->ios.timing == MMC_TIMING_LEGACY)
67162306a36Sopenharmony_ci		clock_fixup = esdhc->clk_fixup->sd_dflt_max_clk;
67262306a36Sopenharmony_ci	else if (esdhc->clk_fixup)
67362306a36Sopenharmony_ci		clock_fixup = esdhc->clk_fixup->max_clk[host->mmc->ios.timing];
67462306a36Sopenharmony_ci
67562306a36Sopenharmony_ci	if (clock_fixup == 0 || clock < clock_fixup)
67662306a36Sopenharmony_ci		clock_fixup = clock;
67762306a36Sopenharmony_ci
67862306a36Sopenharmony_ci	/* Calculate pre_div and div. */
67962306a36Sopenharmony_ci	while (host->max_clk / pre_div / 16 > clock_fixup && pre_div < 256)
68062306a36Sopenharmony_ci		pre_div *= 2;
68162306a36Sopenharmony_ci
68262306a36Sopenharmony_ci	while (host->max_clk / pre_div / div > clock_fixup && div < 16)
68362306a36Sopenharmony_ci		div++;
68462306a36Sopenharmony_ci
68562306a36Sopenharmony_ci	esdhc->div_ratio = pre_div * div;
68662306a36Sopenharmony_ci
68762306a36Sopenharmony_ci	/* Limit clock division for HS400 200MHz clock for quirk. */
68862306a36Sopenharmony_ci	if (esdhc->quirk_limited_clk_division &&
68962306a36Sopenharmony_ci	    clock == MMC_HS200_MAX_DTR &&
69062306a36Sopenharmony_ci	    (host->mmc->ios.timing == MMC_TIMING_MMC_HS400 ||
69162306a36Sopenharmony_ci	     host->flags & SDHCI_HS400_TUNING)) {
69262306a36Sopenharmony_ci		if (esdhc->div_ratio <= 4) {
69362306a36Sopenharmony_ci			pre_div = 4;
69462306a36Sopenharmony_ci			div = 1;
69562306a36Sopenharmony_ci		} else if (esdhc->div_ratio <= 8) {
69662306a36Sopenharmony_ci			pre_div = 4;
69762306a36Sopenharmony_ci			div = 2;
69862306a36Sopenharmony_ci		} else if (esdhc->div_ratio <= 12) {
69962306a36Sopenharmony_ci			pre_div = 4;
70062306a36Sopenharmony_ci			div = 3;
70162306a36Sopenharmony_ci		} else {
70262306a36Sopenharmony_ci			pr_warn("%s: using unsupported clock division.\n",
70362306a36Sopenharmony_ci				mmc_hostname(host->mmc));
70462306a36Sopenharmony_ci		}
70562306a36Sopenharmony_ci		esdhc->div_ratio = pre_div * div;
70662306a36Sopenharmony_ci	}
70762306a36Sopenharmony_ci
70862306a36Sopenharmony_ci	host->mmc->actual_clock = host->max_clk / esdhc->div_ratio;
70962306a36Sopenharmony_ci
71062306a36Sopenharmony_ci	dev_dbg(mmc_dev(host->mmc), "desired SD clock: %d, actual: %d\n",
71162306a36Sopenharmony_ci		clock, host->mmc->actual_clock);
71262306a36Sopenharmony_ci
71362306a36Sopenharmony_ci	/* Set clock division into register. */
71462306a36Sopenharmony_ci	pre_div >>= 1;
71562306a36Sopenharmony_ci	div--;
71662306a36Sopenharmony_ci
71762306a36Sopenharmony_ci	esdhc_clock_enable(host, false);
71862306a36Sopenharmony_ci
71962306a36Sopenharmony_ci	temp = sdhci_readl(host, ESDHC_SYSTEM_CONTROL);
72062306a36Sopenharmony_ci	temp &= ~ESDHC_CLOCK_MASK;
72162306a36Sopenharmony_ci	temp |= ((div << ESDHC_DIVIDER_SHIFT) |
72262306a36Sopenharmony_ci		(pre_div << ESDHC_PREDIV_SHIFT));
72362306a36Sopenharmony_ci	sdhci_writel(host, temp, ESDHC_SYSTEM_CONTROL);
72462306a36Sopenharmony_ci
72562306a36Sopenharmony_ci	/*
72662306a36Sopenharmony_ci	 * Wait max 20 ms. If vendor version is 2.2 or lower, do not
72762306a36Sopenharmony_ci	 * wait clock stable bit which does not exist.
72862306a36Sopenharmony_ci	 */
72962306a36Sopenharmony_ci	timeout = ktime_add_ms(ktime_get(), 20);
73062306a36Sopenharmony_ci	while (esdhc->vendor_ver > VENDOR_V_22) {
73162306a36Sopenharmony_ci		bool timedout = ktime_after(ktime_get(), timeout);
73262306a36Sopenharmony_ci
73362306a36Sopenharmony_ci		if (sdhci_readl(host, ESDHC_PRSSTAT) & ESDHC_CLOCK_STABLE)
73462306a36Sopenharmony_ci			break;
73562306a36Sopenharmony_ci		if (timedout) {
73662306a36Sopenharmony_ci			pr_err("%s: Internal clock never stabilised.\n",
73762306a36Sopenharmony_ci				mmc_hostname(host->mmc));
73862306a36Sopenharmony_ci			break;
73962306a36Sopenharmony_ci		}
74062306a36Sopenharmony_ci		usleep_range(10, 20);
74162306a36Sopenharmony_ci	}
74262306a36Sopenharmony_ci
74362306a36Sopenharmony_ci	/* Additional setting for HS400. */
74462306a36Sopenharmony_ci	if (host->mmc->ios.timing == MMC_TIMING_MMC_HS400 &&
74562306a36Sopenharmony_ci	    clock == MMC_HS200_MAX_DTR) {
74662306a36Sopenharmony_ci		temp = sdhci_readl(host, ESDHC_TBCTL);
74762306a36Sopenharmony_ci		sdhci_writel(host, temp | ESDHC_HS400_MODE, ESDHC_TBCTL);
74862306a36Sopenharmony_ci		temp = sdhci_readl(host, ESDHC_SDCLKCTL);
74962306a36Sopenharmony_ci		sdhci_writel(host, temp | ESDHC_CMD_CLK_CTL, ESDHC_SDCLKCTL);
75062306a36Sopenharmony_ci		esdhc_clock_enable(host, true);
75162306a36Sopenharmony_ci
75262306a36Sopenharmony_ci		temp = sdhci_readl(host, ESDHC_DLLCFG0);
75362306a36Sopenharmony_ci		temp |= ESDHC_DLL_ENABLE;
75462306a36Sopenharmony_ci		if (host->mmc->actual_clock == MMC_HS200_MAX_DTR)
75562306a36Sopenharmony_ci			temp |= ESDHC_DLL_FREQ_SEL;
75662306a36Sopenharmony_ci		sdhci_writel(host, temp, ESDHC_DLLCFG0);
75762306a36Sopenharmony_ci
75862306a36Sopenharmony_ci		temp |= ESDHC_DLL_RESET;
75962306a36Sopenharmony_ci		sdhci_writel(host, temp, ESDHC_DLLCFG0);
76062306a36Sopenharmony_ci		udelay(1);
76162306a36Sopenharmony_ci		temp &= ~ESDHC_DLL_RESET;
76262306a36Sopenharmony_ci		sdhci_writel(host, temp, ESDHC_DLLCFG0);
76362306a36Sopenharmony_ci
76462306a36Sopenharmony_ci		/* Wait max 20 ms */
76562306a36Sopenharmony_ci		if (read_poll_timeout(sdhci_readl, temp,
76662306a36Sopenharmony_ci				      temp & ESDHC_DLL_STS_SLV_LOCK,
76762306a36Sopenharmony_ci				      10, 20000, false,
76862306a36Sopenharmony_ci				      host, ESDHC_DLLSTAT0))
76962306a36Sopenharmony_ci			pr_err("%s: timeout for delay chain lock.\n",
77062306a36Sopenharmony_ci			       mmc_hostname(host->mmc));
77162306a36Sopenharmony_ci
77262306a36Sopenharmony_ci		temp = sdhci_readl(host, ESDHC_TBCTL);
77362306a36Sopenharmony_ci		sdhci_writel(host, temp | ESDHC_HS400_WNDW_ADJUST, ESDHC_TBCTL);
77462306a36Sopenharmony_ci
77562306a36Sopenharmony_ci		esdhc_clock_enable(host, false);
77662306a36Sopenharmony_ci		esdhc_flush_async_fifo(host);
77762306a36Sopenharmony_ci	}
77862306a36Sopenharmony_ci	esdhc_clock_enable(host, true);
77962306a36Sopenharmony_ci}
78062306a36Sopenharmony_ci
78162306a36Sopenharmony_cistatic void esdhc_pltfm_set_bus_width(struct sdhci_host *host, int width)
78262306a36Sopenharmony_ci{
78362306a36Sopenharmony_ci	u32 ctrl;
78462306a36Sopenharmony_ci
78562306a36Sopenharmony_ci	ctrl = sdhci_readl(host, ESDHC_PROCTL);
78662306a36Sopenharmony_ci	ctrl &= (~ESDHC_CTRL_BUSWIDTH_MASK);
78762306a36Sopenharmony_ci	switch (width) {
78862306a36Sopenharmony_ci	case MMC_BUS_WIDTH_8:
78962306a36Sopenharmony_ci		ctrl |= ESDHC_CTRL_8BITBUS;
79062306a36Sopenharmony_ci		break;
79162306a36Sopenharmony_ci
79262306a36Sopenharmony_ci	case MMC_BUS_WIDTH_4:
79362306a36Sopenharmony_ci		ctrl |= ESDHC_CTRL_4BITBUS;
79462306a36Sopenharmony_ci		break;
79562306a36Sopenharmony_ci
79662306a36Sopenharmony_ci	default:
79762306a36Sopenharmony_ci		break;
79862306a36Sopenharmony_ci	}
79962306a36Sopenharmony_ci
80062306a36Sopenharmony_ci	sdhci_writel(host, ctrl, ESDHC_PROCTL);
80162306a36Sopenharmony_ci}
80262306a36Sopenharmony_ci
80362306a36Sopenharmony_cistatic void esdhc_reset(struct sdhci_host *host, u8 mask)
80462306a36Sopenharmony_ci{
80562306a36Sopenharmony_ci	struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
80662306a36Sopenharmony_ci	struct sdhci_esdhc *esdhc = sdhci_pltfm_priv(pltfm_host);
80762306a36Sopenharmony_ci	u32 val, bus_width = 0;
80862306a36Sopenharmony_ci
80962306a36Sopenharmony_ci	/*
81062306a36Sopenharmony_ci	 * Add delay to make sure all the DMA transfers are finished
81162306a36Sopenharmony_ci	 * for quirk.
81262306a36Sopenharmony_ci	 */
81362306a36Sopenharmony_ci	if (esdhc->quirk_delay_before_data_reset &&
81462306a36Sopenharmony_ci	    (mask & SDHCI_RESET_DATA) &&
81562306a36Sopenharmony_ci	    (host->flags & SDHCI_REQ_USE_DMA))
81662306a36Sopenharmony_ci		mdelay(5);
81762306a36Sopenharmony_ci
81862306a36Sopenharmony_ci	/*
81962306a36Sopenharmony_ci	 * Save bus-width for eSDHC whose vendor version is 2.2
82062306a36Sopenharmony_ci	 * or lower for data reset.
82162306a36Sopenharmony_ci	 */
82262306a36Sopenharmony_ci	if ((mask & SDHCI_RESET_DATA) &&
82362306a36Sopenharmony_ci	    (esdhc->vendor_ver <= VENDOR_V_22)) {
82462306a36Sopenharmony_ci		val = sdhci_readl(host, ESDHC_PROCTL);
82562306a36Sopenharmony_ci		bus_width = val & ESDHC_CTRL_BUSWIDTH_MASK;
82662306a36Sopenharmony_ci	}
82762306a36Sopenharmony_ci
82862306a36Sopenharmony_ci	sdhci_reset(host, mask);
82962306a36Sopenharmony_ci
83062306a36Sopenharmony_ci	/*
83162306a36Sopenharmony_ci	 * Restore bus-width setting and interrupt registers for eSDHC
83262306a36Sopenharmony_ci	 * whose vendor version is 2.2 or lower for data reset.
83362306a36Sopenharmony_ci	 */
83462306a36Sopenharmony_ci	if ((mask & SDHCI_RESET_DATA) &&
83562306a36Sopenharmony_ci	    (esdhc->vendor_ver <= VENDOR_V_22)) {
83662306a36Sopenharmony_ci		val = sdhci_readl(host, ESDHC_PROCTL);
83762306a36Sopenharmony_ci		val &= ~ESDHC_CTRL_BUSWIDTH_MASK;
83862306a36Sopenharmony_ci		val |= bus_width;
83962306a36Sopenharmony_ci		sdhci_writel(host, val, ESDHC_PROCTL);
84062306a36Sopenharmony_ci
84162306a36Sopenharmony_ci		sdhci_writel(host, host->ier, SDHCI_INT_ENABLE);
84262306a36Sopenharmony_ci		sdhci_writel(host, host->ier, SDHCI_SIGNAL_ENABLE);
84362306a36Sopenharmony_ci	}
84462306a36Sopenharmony_ci
84562306a36Sopenharmony_ci	/*
84662306a36Sopenharmony_ci	 * Some bits have to be cleaned manually for eSDHC whose spec
84762306a36Sopenharmony_ci	 * version is higher than 3.0 for all reset.
84862306a36Sopenharmony_ci	 */
84962306a36Sopenharmony_ci	if ((mask & SDHCI_RESET_ALL) &&
85062306a36Sopenharmony_ci	    (esdhc->spec_ver >= SDHCI_SPEC_300)) {
85162306a36Sopenharmony_ci		val = sdhci_readl(host, ESDHC_TBCTL);
85262306a36Sopenharmony_ci		val &= ~ESDHC_TB_EN;
85362306a36Sopenharmony_ci		sdhci_writel(host, val, ESDHC_TBCTL);
85462306a36Sopenharmony_ci
85562306a36Sopenharmony_ci		/*
85662306a36Sopenharmony_ci		 * Initialize eSDHC_DLLCFG1[DLL_PD_PULSE_STRETCH_SEL] to
85762306a36Sopenharmony_ci		 * 0 for quirk.
85862306a36Sopenharmony_ci		 */
85962306a36Sopenharmony_ci		if (esdhc->quirk_unreliable_pulse_detection) {
86062306a36Sopenharmony_ci			val = sdhci_readl(host, ESDHC_DLLCFG1);
86162306a36Sopenharmony_ci			val &= ~ESDHC_DLL_PD_PULSE_STRETCH_SEL;
86262306a36Sopenharmony_ci			sdhci_writel(host, val, ESDHC_DLLCFG1);
86362306a36Sopenharmony_ci		}
86462306a36Sopenharmony_ci	}
86562306a36Sopenharmony_ci}
86662306a36Sopenharmony_ci
86762306a36Sopenharmony_ci/* The SCFG, Supplemental Configuration Unit, provides SoC specific
86862306a36Sopenharmony_ci * configuration and status registers for the device. There is a
86962306a36Sopenharmony_ci * SDHC IO VSEL control register on SCFG for some platforms. It's
87062306a36Sopenharmony_ci * used to support SDHC IO voltage switching.
87162306a36Sopenharmony_ci */
87262306a36Sopenharmony_cistatic const struct of_device_id scfg_device_ids[] = {
87362306a36Sopenharmony_ci	{ .compatible = "fsl,t1040-scfg", },
87462306a36Sopenharmony_ci	{ .compatible = "fsl,ls1012a-scfg", },
87562306a36Sopenharmony_ci	{ .compatible = "fsl,ls1046a-scfg", },
87662306a36Sopenharmony_ci	{}
87762306a36Sopenharmony_ci};
87862306a36Sopenharmony_ci
87962306a36Sopenharmony_ci/* SDHC IO VSEL control register definition */
88062306a36Sopenharmony_ci#define SCFG_SDHCIOVSELCR	0x408
88162306a36Sopenharmony_ci#define SDHCIOVSELCR_TGLEN	0x80000000
88262306a36Sopenharmony_ci#define SDHCIOVSELCR_VSELVAL	0x60000000
88362306a36Sopenharmony_ci#define SDHCIOVSELCR_SDHC_VS	0x00000001
88462306a36Sopenharmony_ci
88562306a36Sopenharmony_cistatic int esdhc_signal_voltage_switch(struct mmc_host *mmc,
88662306a36Sopenharmony_ci				       struct mmc_ios *ios)
88762306a36Sopenharmony_ci{
88862306a36Sopenharmony_ci	struct sdhci_host *host = mmc_priv(mmc);
88962306a36Sopenharmony_ci	struct device_node *scfg_node;
89062306a36Sopenharmony_ci	void __iomem *scfg_base = NULL;
89162306a36Sopenharmony_ci	u32 sdhciovselcr;
89262306a36Sopenharmony_ci	u32 val;
89362306a36Sopenharmony_ci
89462306a36Sopenharmony_ci	/*
89562306a36Sopenharmony_ci	 * Signal Voltage Switching is only applicable for Host Controllers
89662306a36Sopenharmony_ci	 * v3.00 and above.
89762306a36Sopenharmony_ci	 */
89862306a36Sopenharmony_ci	if (host->version < SDHCI_SPEC_300)
89962306a36Sopenharmony_ci		return 0;
90062306a36Sopenharmony_ci
90162306a36Sopenharmony_ci	val = sdhci_readl(host, ESDHC_PROCTL);
90262306a36Sopenharmony_ci
90362306a36Sopenharmony_ci	switch (ios->signal_voltage) {
90462306a36Sopenharmony_ci	case MMC_SIGNAL_VOLTAGE_330:
90562306a36Sopenharmony_ci		val &= ~ESDHC_VOLT_SEL;
90662306a36Sopenharmony_ci		sdhci_writel(host, val, ESDHC_PROCTL);
90762306a36Sopenharmony_ci		return 0;
90862306a36Sopenharmony_ci	case MMC_SIGNAL_VOLTAGE_180:
90962306a36Sopenharmony_ci		scfg_node = of_find_matching_node(NULL, scfg_device_ids);
91062306a36Sopenharmony_ci		if (scfg_node)
91162306a36Sopenharmony_ci			scfg_base = of_iomap(scfg_node, 0);
91262306a36Sopenharmony_ci		of_node_put(scfg_node);
91362306a36Sopenharmony_ci		if (scfg_base) {
91462306a36Sopenharmony_ci			sdhciovselcr = SDHCIOVSELCR_TGLEN |
91562306a36Sopenharmony_ci				       SDHCIOVSELCR_VSELVAL;
91662306a36Sopenharmony_ci			iowrite32be(sdhciovselcr,
91762306a36Sopenharmony_ci				scfg_base + SCFG_SDHCIOVSELCR);
91862306a36Sopenharmony_ci
91962306a36Sopenharmony_ci			val |= ESDHC_VOLT_SEL;
92062306a36Sopenharmony_ci			sdhci_writel(host, val, ESDHC_PROCTL);
92162306a36Sopenharmony_ci			mdelay(5);
92262306a36Sopenharmony_ci
92362306a36Sopenharmony_ci			sdhciovselcr = SDHCIOVSELCR_TGLEN |
92462306a36Sopenharmony_ci				       SDHCIOVSELCR_SDHC_VS;
92562306a36Sopenharmony_ci			iowrite32be(sdhciovselcr,
92662306a36Sopenharmony_ci				scfg_base + SCFG_SDHCIOVSELCR);
92762306a36Sopenharmony_ci			iounmap(scfg_base);
92862306a36Sopenharmony_ci		} else {
92962306a36Sopenharmony_ci			val |= ESDHC_VOLT_SEL;
93062306a36Sopenharmony_ci			sdhci_writel(host, val, ESDHC_PROCTL);
93162306a36Sopenharmony_ci		}
93262306a36Sopenharmony_ci		return 0;
93362306a36Sopenharmony_ci	default:
93462306a36Sopenharmony_ci		return 0;
93562306a36Sopenharmony_ci	}
93662306a36Sopenharmony_ci}
93762306a36Sopenharmony_ci
93862306a36Sopenharmony_cistatic struct soc_device_attribute soc_tuning_erratum_type1[] = {
93962306a36Sopenharmony_ci	{ .family = "QorIQ T1023", },
94062306a36Sopenharmony_ci	{ .family = "QorIQ T1040", },
94162306a36Sopenharmony_ci	{ .family = "QorIQ T2080", },
94262306a36Sopenharmony_ci	{ .family = "QorIQ LS1021A", },
94362306a36Sopenharmony_ci	{ /* sentinel */ }
94462306a36Sopenharmony_ci};
94562306a36Sopenharmony_ci
94662306a36Sopenharmony_cistatic struct soc_device_attribute soc_tuning_erratum_type2[] = {
94762306a36Sopenharmony_ci	{ .family = "QorIQ LS1012A", },
94862306a36Sopenharmony_ci	{ .family = "QorIQ LS1043A", },
94962306a36Sopenharmony_ci	{ .family = "QorIQ LS1046A", },
95062306a36Sopenharmony_ci	{ .family = "QorIQ LS1080A", },
95162306a36Sopenharmony_ci	{ .family = "QorIQ LS2080A", },
95262306a36Sopenharmony_ci	{ .family = "QorIQ LA1575A", },
95362306a36Sopenharmony_ci	{ /* sentinel */ }
95462306a36Sopenharmony_ci};
95562306a36Sopenharmony_ci
95662306a36Sopenharmony_cistatic void esdhc_tuning_block_enable(struct sdhci_host *host, bool enable)
95762306a36Sopenharmony_ci{
95862306a36Sopenharmony_ci	u32 val;
95962306a36Sopenharmony_ci
96062306a36Sopenharmony_ci	esdhc_clock_enable(host, false);
96162306a36Sopenharmony_ci	esdhc_flush_async_fifo(host);
96262306a36Sopenharmony_ci
96362306a36Sopenharmony_ci	val = sdhci_readl(host, ESDHC_TBCTL);
96462306a36Sopenharmony_ci	if (enable)
96562306a36Sopenharmony_ci		val |= ESDHC_TB_EN;
96662306a36Sopenharmony_ci	else
96762306a36Sopenharmony_ci		val &= ~ESDHC_TB_EN;
96862306a36Sopenharmony_ci	sdhci_writel(host, val, ESDHC_TBCTL);
96962306a36Sopenharmony_ci
97062306a36Sopenharmony_ci	esdhc_clock_enable(host, true);
97162306a36Sopenharmony_ci}
97262306a36Sopenharmony_ci
97362306a36Sopenharmony_cistatic void esdhc_tuning_window_ptr(struct sdhci_host *host, u8 *window_start,
97462306a36Sopenharmony_ci				    u8 *window_end)
97562306a36Sopenharmony_ci{
97662306a36Sopenharmony_ci	u32 val;
97762306a36Sopenharmony_ci
97862306a36Sopenharmony_ci	/* Write TBCTL[11:8]=4'h8 */
97962306a36Sopenharmony_ci	val = sdhci_readl(host, ESDHC_TBCTL);
98062306a36Sopenharmony_ci	val &= ~(0xf << 8);
98162306a36Sopenharmony_ci	val |= 8 << 8;
98262306a36Sopenharmony_ci	sdhci_writel(host, val, ESDHC_TBCTL);
98362306a36Sopenharmony_ci
98462306a36Sopenharmony_ci	mdelay(1);
98562306a36Sopenharmony_ci
98662306a36Sopenharmony_ci	/* Read TBCTL[31:0] register and rewrite again */
98762306a36Sopenharmony_ci	val = sdhci_readl(host, ESDHC_TBCTL);
98862306a36Sopenharmony_ci	sdhci_writel(host, val, ESDHC_TBCTL);
98962306a36Sopenharmony_ci
99062306a36Sopenharmony_ci	mdelay(1);
99162306a36Sopenharmony_ci
99262306a36Sopenharmony_ci	/* Read the TBSTAT[31:0] register twice */
99362306a36Sopenharmony_ci	val = sdhci_readl(host, ESDHC_TBSTAT);
99462306a36Sopenharmony_ci	val = sdhci_readl(host, ESDHC_TBSTAT);
99562306a36Sopenharmony_ci
99662306a36Sopenharmony_ci	*window_end = val & 0xff;
99762306a36Sopenharmony_ci	*window_start = (val >> 8) & 0xff;
99862306a36Sopenharmony_ci}
99962306a36Sopenharmony_ci
100062306a36Sopenharmony_cistatic void esdhc_prepare_sw_tuning(struct sdhci_host *host, u8 *window_start,
100162306a36Sopenharmony_ci				    u8 *window_end)
100262306a36Sopenharmony_ci{
100362306a36Sopenharmony_ci	struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
100462306a36Sopenharmony_ci	struct sdhci_esdhc *esdhc = sdhci_pltfm_priv(pltfm_host);
100562306a36Sopenharmony_ci	u8 start_ptr, end_ptr;
100662306a36Sopenharmony_ci
100762306a36Sopenharmony_ci	if (esdhc->quirk_tuning_erratum_type1) {
100862306a36Sopenharmony_ci		*window_start = 5 * esdhc->div_ratio;
100962306a36Sopenharmony_ci		*window_end = 3 * esdhc->div_ratio;
101062306a36Sopenharmony_ci		return;
101162306a36Sopenharmony_ci	}
101262306a36Sopenharmony_ci
101362306a36Sopenharmony_ci	esdhc_tuning_window_ptr(host, &start_ptr, &end_ptr);
101462306a36Sopenharmony_ci
101562306a36Sopenharmony_ci	/* Reset data lines by setting ESDHCCTL[RSTD] */
101662306a36Sopenharmony_ci	sdhci_reset(host, SDHCI_RESET_DATA);
101762306a36Sopenharmony_ci	/* Write 32'hFFFF_FFFF to IRQSTAT register */
101862306a36Sopenharmony_ci	sdhci_writel(host, 0xFFFFFFFF, SDHCI_INT_STATUS);
101962306a36Sopenharmony_ci
102062306a36Sopenharmony_ci	/* If TBSTAT[15:8]-TBSTAT[7:0] > (4 * div_ratio) + 2
102162306a36Sopenharmony_ci	 * or TBSTAT[7:0]-TBSTAT[15:8] > (4 * div_ratio) + 2,
102262306a36Sopenharmony_ci	 * then program TBPTR[TB_WNDW_END_PTR] = 4 * div_ratio
102362306a36Sopenharmony_ci	 * and program TBPTR[TB_WNDW_START_PTR] = 8 * div_ratio.
102462306a36Sopenharmony_ci	 */
102562306a36Sopenharmony_ci
102662306a36Sopenharmony_ci	if (abs(start_ptr - end_ptr) > (4 * esdhc->div_ratio + 2)) {
102762306a36Sopenharmony_ci		*window_start = 8 * esdhc->div_ratio;
102862306a36Sopenharmony_ci		*window_end = 4 * esdhc->div_ratio;
102962306a36Sopenharmony_ci	} else {
103062306a36Sopenharmony_ci		*window_start = 5 * esdhc->div_ratio;
103162306a36Sopenharmony_ci		*window_end = 3 * esdhc->div_ratio;
103262306a36Sopenharmony_ci	}
103362306a36Sopenharmony_ci}
103462306a36Sopenharmony_ci
103562306a36Sopenharmony_cistatic int esdhc_execute_sw_tuning(struct mmc_host *mmc, u32 opcode,
103662306a36Sopenharmony_ci				   u8 window_start, u8 window_end)
103762306a36Sopenharmony_ci{
103862306a36Sopenharmony_ci	struct sdhci_host *host = mmc_priv(mmc);
103962306a36Sopenharmony_ci	struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
104062306a36Sopenharmony_ci	struct sdhci_esdhc *esdhc = sdhci_pltfm_priv(pltfm_host);
104162306a36Sopenharmony_ci	u32 val;
104262306a36Sopenharmony_ci	int ret;
104362306a36Sopenharmony_ci
104462306a36Sopenharmony_ci	/* Program TBPTR[TB_WNDW_END_PTR] and TBPTR[TB_WNDW_START_PTR] */
104562306a36Sopenharmony_ci	val = ((u32)window_start << ESDHC_WNDW_STRT_PTR_SHIFT) &
104662306a36Sopenharmony_ci	      ESDHC_WNDW_STRT_PTR_MASK;
104762306a36Sopenharmony_ci	val |= window_end & ESDHC_WNDW_END_PTR_MASK;
104862306a36Sopenharmony_ci	sdhci_writel(host, val, ESDHC_TBPTR);
104962306a36Sopenharmony_ci
105062306a36Sopenharmony_ci	/* Program the software tuning mode by setting TBCTL[TB_MODE]=2'h3 */
105162306a36Sopenharmony_ci	val = sdhci_readl(host, ESDHC_TBCTL);
105262306a36Sopenharmony_ci	val &= ~ESDHC_TB_MODE_MASK;
105362306a36Sopenharmony_ci	val |= ESDHC_TB_MODE_SW;
105462306a36Sopenharmony_ci	sdhci_writel(host, val, ESDHC_TBCTL);
105562306a36Sopenharmony_ci
105662306a36Sopenharmony_ci	esdhc->in_sw_tuning = true;
105762306a36Sopenharmony_ci	ret = sdhci_execute_tuning(mmc, opcode);
105862306a36Sopenharmony_ci	esdhc->in_sw_tuning = false;
105962306a36Sopenharmony_ci	return ret;
106062306a36Sopenharmony_ci}
106162306a36Sopenharmony_ci
106262306a36Sopenharmony_cistatic int esdhc_execute_tuning(struct mmc_host *mmc, u32 opcode)
106362306a36Sopenharmony_ci{
106462306a36Sopenharmony_ci	struct sdhci_host *host = mmc_priv(mmc);
106562306a36Sopenharmony_ci	struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
106662306a36Sopenharmony_ci	struct sdhci_esdhc *esdhc = sdhci_pltfm_priv(pltfm_host);
106762306a36Sopenharmony_ci	u8 window_start, window_end;
106862306a36Sopenharmony_ci	int ret, retries = 1;
106962306a36Sopenharmony_ci	bool hs400_tuning;
107062306a36Sopenharmony_ci	unsigned int clk;
107162306a36Sopenharmony_ci	u32 val;
107262306a36Sopenharmony_ci
107362306a36Sopenharmony_ci	/* For tuning mode, the sd clock divisor value
107462306a36Sopenharmony_ci	 * must be larger than 3 according to reference manual.
107562306a36Sopenharmony_ci	 */
107662306a36Sopenharmony_ci	clk = esdhc->peripheral_clock / 3;
107762306a36Sopenharmony_ci	if (host->clock > clk)
107862306a36Sopenharmony_ci		esdhc_of_set_clock(host, clk);
107962306a36Sopenharmony_ci
108062306a36Sopenharmony_ci	esdhc_tuning_block_enable(host, true);
108162306a36Sopenharmony_ci
108262306a36Sopenharmony_ci	/*
108362306a36Sopenharmony_ci	 * The eSDHC controller takes the data timeout value into account
108462306a36Sopenharmony_ci	 * during tuning. If the SD card is too slow sending the response, the
108562306a36Sopenharmony_ci	 * timer will expire and a "Buffer Read Ready" interrupt without data
108662306a36Sopenharmony_ci	 * is triggered. This leads to tuning errors.
108762306a36Sopenharmony_ci	 *
108862306a36Sopenharmony_ci	 * Just set the timeout to the maximum value because the core will
108962306a36Sopenharmony_ci	 * already take care of it in sdhci_send_tuning().
109062306a36Sopenharmony_ci	 */
109162306a36Sopenharmony_ci	sdhci_writeb(host, 0xe, SDHCI_TIMEOUT_CONTROL);
109262306a36Sopenharmony_ci
109362306a36Sopenharmony_ci	hs400_tuning = host->flags & SDHCI_HS400_TUNING;
109462306a36Sopenharmony_ci
109562306a36Sopenharmony_ci	do {
109662306a36Sopenharmony_ci		if (esdhc->quirk_limited_clk_division &&
109762306a36Sopenharmony_ci		    hs400_tuning)
109862306a36Sopenharmony_ci			esdhc_of_set_clock(host, host->clock);
109962306a36Sopenharmony_ci
110062306a36Sopenharmony_ci		/* Do HW tuning */
110162306a36Sopenharmony_ci		val = sdhci_readl(host, ESDHC_TBCTL);
110262306a36Sopenharmony_ci		val &= ~ESDHC_TB_MODE_MASK;
110362306a36Sopenharmony_ci		val |= ESDHC_TB_MODE_3;
110462306a36Sopenharmony_ci		sdhci_writel(host, val, ESDHC_TBCTL);
110562306a36Sopenharmony_ci
110662306a36Sopenharmony_ci		ret = sdhci_execute_tuning(mmc, opcode);
110762306a36Sopenharmony_ci		if (ret)
110862306a36Sopenharmony_ci			break;
110962306a36Sopenharmony_ci
111062306a36Sopenharmony_ci		/* For type2 affected platforms of the tuning erratum,
111162306a36Sopenharmony_ci		 * tuning may succeed although eSDHC might not have
111262306a36Sopenharmony_ci		 * tuned properly. Need to check tuning window.
111362306a36Sopenharmony_ci		 */
111462306a36Sopenharmony_ci		if (esdhc->quirk_tuning_erratum_type2 &&
111562306a36Sopenharmony_ci		    !host->tuning_err) {
111662306a36Sopenharmony_ci			esdhc_tuning_window_ptr(host, &window_start,
111762306a36Sopenharmony_ci						&window_end);
111862306a36Sopenharmony_ci			if (abs(window_start - window_end) >
111962306a36Sopenharmony_ci			    (4 * esdhc->div_ratio + 2))
112062306a36Sopenharmony_ci				host->tuning_err = -EAGAIN;
112162306a36Sopenharmony_ci		}
112262306a36Sopenharmony_ci
112362306a36Sopenharmony_ci		/* If HW tuning fails and triggers erratum,
112462306a36Sopenharmony_ci		 * try workaround.
112562306a36Sopenharmony_ci		 */
112662306a36Sopenharmony_ci		ret = host->tuning_err;
112762306a36Sopenharmony_ci		if (ret == -EAGAIN &&
112862306a36Sopenharmony_ci		    (esdhc->quirk_tuning_erratum_type1 ||
112962306a36Sopenharmony_ci		     esdhc->quirk_tuning_erratum_type2)) {
113062306a36Sopenharmony_ci			/* Recover HS400 tuning flag */
113162306a36Sopenharmony_ci			if (hs400_tuning)
113262306a36Sopenharmony_ci				host->flags |= SDHCI_HS400_TUNING;
113362306a36Sopenharmony_ci			pr_info("%s: Hold on to use fixed sampling clock. Try SW tuning!\n",
113462306a36Sopenharmony_ci				mmc_hostname(mmc));
113562306a36Sopenharmony_ci			/* Do SW tuning */
113662306a36Sopenharmony_ci			esdhc_prepare_sw_tuning(host, &window_start,
113762306a36Sopenharmony_ci						&window_end);
113862306a36Sopenharmony_ci			ret = esdhc_execute_sw_tuning(mmc, opcode,
113962306a36Sopenharmony_ci						      window_start,
114062306a36Sopenharmony_ci						      window_end);
114162306a36Sopenharmony_ci			if (ret)
114262306a36Sopenharmony_ci				break;
114362306a36Sopenharmony_ci
114462306a36Sopenharmony_ci			/* Retry both HW/SW tuning with reduced clock. */
114562306a36Sopenharmony_ci			ret = host->tuning_err;
114662306a36Sopenharmony_ci			if (ret == -EAGAIN && retries) {
114762306a36Sopenharmony_ci				/* Recover HS400 tuning flag */
114862306a36Sopenharmony_ci				if (hs400_tuning)
114962306a36Sopenharmony_ci					host->flags |= SDHCI_HS400_TUNING;
115062306a36Sopenharmony_ci
115162306a36Sopenharmony_ci				clk = host->max_clk / (esdhc->div_ratio + 1);
115262306a36Sopenharmony_ci				esdhc_of_set_clock(host, clk);
115362306a36Sopenharmony_ci				pr_info("%s: Hold on to use fixed sampling clock. Try tuning with reduced clock!\n",
115462306a36Sopenharmony_ci					mmc_hostname(mmc));
115562306a36Sopenharmony_ci			} else {
115662306a36Sopenharmony_ci				break;
115762306a36Sopenharmony_ci			}
115862306a36Sopenharmony_ci		} else {
115962306a36Sopenharmony_ci			break;
116062306a36Sopenharmony_ci		}
116162306a36Sopenharmony_ci	} while (retries--);
116262306a36Sopenharmony_ci
116362306a36Sopenharmony_ci	if (ret) {
116462306a36Sopenharmony_ci		esdhc_tuning_block_enable(host, false);
116562306a36Sopenharmony_ci	} else if (hs400_tuning) {
116662306a36Sopenharmony_ci		val = sdhci_readl(host, ESDHC_SDTIMNGCTL);
116762306a36Sopenharmony_ci		val |= ESDHC_FLW_CTL_BG;
116862306a36Sopenharmony_ci		sdhci_writel(host, val, ESDHC_SDTIMNGCTL);
116962306a36Sopenharmony_ci	}
117062306a36Sopenharmony_ci
117162306a36Sopenharmony_ci	return ret;
117262306a36Sopenharmony_ci}
117362306a36Sopenharmony_ci
117462306a36Sopenharmony_cistatic void esdhc_set_uhs_signaling(struct sdhci_host *host,
117562306a36Sopenharmony_ci				   unsigned int timing)
117662306a36Sopenharmony_ci{
117762306a36Sopenharmony_ci	u32 val;
117862306a36Sopenharmony_ci
117962306a36Sopenharmony_ci	/*
118062306a36Sopenharmony_ci	 * There are specific registers setting for HS400 mode.
118162306a36Sopenharmony_ci	 * Clean all of them if controller is in HS400 mode to
118262306a36Sopenharmony_ci	 * exit HS400 mode before re-setting any speed mode.
118362306a36Sopenharmony_ci	 */
118462306a36Sopenharmony_ci	val = sdhci_readl(host, ESDHC_TBCTL);
118562306a36Sopenharmony_ci	if (val & ESDHC_HS400_MODE) {
118662306a36Sopenharmony_ci		val = sdhci_readl(host, ESDHC_SDTIMNGCTL);
118762306a36Sopenharmony_ci		val &= ~ESDHC_FLW_CTL_BG;
118862306a36Sopenharmony_ci		sdhci_writel(host, val, ESDHC_SDTIMNGCTL);
118962306a36Sopenharmony_ci
119062306a36Sopenharmony_ci		val = sdhci_readl(host, ESDHC_SDCLKCTL);
119162306a36Sopenharmony_ci		val &= ~ESDHC_CMD_CLK_CTL;
119262306a36Sopenharmony_ci		sdhci_writel(host, val, ESDHC_SDCLKCTL);
119362306a36Sopenharmony_ci
119462306a36Sopenharmony_ci		esdhc_clock_enable(host, false);
119562306a36Sopenharmony_ci		val = sdhci_readl(host, ESDHC_TBCTL);
119662306a36Sopenharmony_ci		val &= ~ESDHC_HS400_MODE;
119762306a36Sopenharmony_ci		sdhci_writel(host, val, ESDHC_TBCTL);
119862306a36Sopenharmony_ci		esdhc_clock_enable(host, true);
119962306a36Sopenharmony_ci
120062306a36Sopenharmony_ci		val = sdhci_readl(host, ESDHC_DLLCFG0);
120162306a36Sopenharmony_ci		val &= ~(ESDHC_DLL_ENABLE | ESDHC_DLL_FREQ_SEL);
120262306a36Sopenharmony_ci		sdhci_writel(host, val, ESDHC_DLLCFG0);
120362306a36Sopenharmony_ci
120462306a36Sopenharmony_ci		val = sdhci_readl(host, ESDHC_TBCTL);
120562306a36Sopenharmony_ci		val &= ~ESDHC_HS400_WNDW_ADJUST;
120662306a36Sopenharmony_ci		sdhci_writel(host, val, ESDHC_TBCTL);
120762306a36Sopenharmony_ci
120862306a36Sopenharmony_ci		esdhc_tuning_block_enable(host, false);
120962306a36Sopenharmony_ci	}
121062306a36Sopenharmony_ci
121162306a36Sopenharmony_ci	if (timing == MMC_TIMING_MMC_HS400)
121262306a36Sopenharmony_ci		esdhc_tuning_block_enable(host, true);
121362306a36Sopenharmony_ci	else
121462306a36Sopenharmony_ci		sdhci_set_uhs_signaling(host, timing);
121562306a36Sopenharmony_ci}
121662306a36Sopenharmony_ci
121762306a36Sopenharmony_cistatic u32 esdhc_irq(struct sdhci_host *host, u32 intmask)
121862306a36Sopenharmony_ci{
121962306a36Sopenharmony_ci	struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
122062306a36Sopenharmony_ci	struct sdhci_esdhc *esdhc = sdhci_pltfm_priv(pltfm_host);
122162306a36Sopenharmony_ci	u32 command;
122262306a36Sopenharmony_ci
122362306a36Sopenharmony_ci	if (esdhc->quirk_trans_complete_erratum) {
122462306a36Sopenharmony_ci		command = SDHCI_GET_CMD(sdhci_readw(host,
122562306a36Sopenharmony_ci					SDHCI_COMMAND));
122662306a36Sopenharmony_ci		if (command == MMC_WRITE_MULTIPLE_BLOCK &&
122762306a36Sopenharmony_ci				sdhci_readw(host, SDHCI_BLOCK_COUNT) &&
122862306a36Sopenharmony_ci				intmask & SDHCI_INT_DATA_END) {
122962306a36Sopenharmony_ci			intmask &= ~SDHCI_INT_DATA_END;
123062306a36Sopenharmony_ci			sdhci_writel(host, SDHCI_INT_DATA_END,
123162306a36Sopenharmony_ci					SDHCI_INT_STATUS);
123262306a36Sopenharmony_ci		}
123362306a36Sopenharmony_ci	}
123462306a36Sopenharmony_ci	return intmask;
123562306a36Sopenharmony_ci}
123662306a36Sopenharmony_ci
123762306a36Sopenharmony_ci#ifdef CONFIG_PM_SLEEP
123862306a36Sopenharmony_cistatic u32 esdhc_proctl;
123962306a36Sopenharmony_cistatic int esdhc_of_suspend(struct device *dev)
124062306a36Sopenharmony_ci{
124162306a36Sopenharmony_ci	struct sdhci_host *host = dev_get_drvdata(dev);
124262306a36Sopenharmony_ci
124362306a36Sopenharmony_ci	esdhc_proctl = sdhci_readl(host, SDHCI_HOST_CONTROL);
124462306a36Sopenharmony_ci
124562306a36Sopenharmony_ci	if (host->tuning_mode != SDHCI_TUNING_MODE_3)
124662306a36Sopenharmony_ci		mmc_retune_needed(host->mmc);
124762306a36Sopenharmony_ci
124862306a36Sopenharmony_ci	return sdhci_suspend_host(host);
124962306a36Sopenharmony_ci}
125062306a36Sopenharmony_ci
125162306a36Sopenharmony_cistatic int esdhc_of_resume(struct device *dev)
125262306a36Sopenharmony_ci{
125362306a36Sopenharmony_ci	struct sdhci_host *host = dev_get_drvdata(dev);
125462306a36Sopenharmony_ci	int ret = sdhci_resume_host(host);
125562306a36Sopenharmony_ci
125662306a36Sopenharmony_ci	if (ret == 0) {
125762306a36Sopenharmony_ci		/* Isn't this already done by sdhci_resume_host() ? --rmk */
125862306a36Sopenharmony_ci		esdhc_of_enable_dma(host);
125962306a36Sopenharmony_ci		sdhci_writel(host, esdhc_proctl, SDHCI_HOST_CONTROL);
126062306a36Sopenharmony_ci	}
126162306a36Sopenharmony_ci	return ret;
126262306a36Sopenharmony_ci}
126362306a36Sopenharmony_ci#endif
126462306a36Sopenharmony_ci
126562306a36Sopenharmony_cistatic SIMPLE_DEV_PM_OPS(esdhc_of_dev_pm_ops,
126662306a36Sopenharmony_ci			esdhc_of_suspend,
126762306a36Sopenharmony_ci			esdhc_of_resume);
126862306a36Sopenharmony_ci
126962306a36Sopenharmony_cistatic const struct sdhci_ops sdhci_esdhc_be_ops = {
127062306a36Sopenharmony_ci	.read_l = esdhc_be_readl,
127162306a36Sopenharmony_ci	.read_w = esdhc_be_readw,
127262306a36Sopenharmony_ci	.read_b = esdhc_be_readb,
127362306a36Sopenharmony_ci	.write_l = esdhc_be_writel,
127462306a36Sopenharmony_ci	.write_w = esdhc_be_writew,
127562306a36Sopenharmony_ci	.write_b = esdhc_be_writeb,
127662306a36Sopenharmony_ci	.set_clock = esdhc_of_set_clock,
127762306a36Sopenharmony_ci	.enable_dma = esdhc_of_enable_dma,
127862306a36Sopenharmony_ci	.get_max_clock = esdhc_of_get_max_clock,
127962306a36Sopenharmony_ci	.get_min_clock = esdhc_of_get_min_clock,
128062306a36Sopenharmony_ci	.adma_workaround = esdhc_of_adma_workaround,
128162306a36Sopenharmony_ci	.set_bus_width = esdhc_pltfm_set_bus_width,
128262306a36Sopenharmony_ci	.reset = esdhc_reset,
128362306a36Sopenharmony_ci	.set_uhs_signaling = esdhc_set_uhs_signaling,
128462306a36Sopenharmony_ci	.irq = esdhc_irq,
128562306a36Sopenharmony_ci};
128662306a36Sopenharmony_ci
128762306a36Sopenharmony_cistatic const struct sdhci_ops sdhci_esdhc_le_ops = {
128862306a36Sopenharmony_ci	.read_l = esdhc_le_readl,
128962306a36Sopenharmony_ci	.read_w = esdhc_le_readw,
129062306a36Sopenharmony_ci	.read_b = esdhc_le_readb,
129162306a36Sopenharmony_ci	.write_l = esdhc_le_writel,
129262306a36Sopenharmony_ci	.write_w = esdhc_le_writew,
129362306a36Sopenharmony_ci	.write_b = esdhc_le_writeb,
129462306a36Sopenharmony_ci	.set_clock = esdhc_of_set_clock,
129562306a36Sopenharmony_ci	.enable_dma = esdhc_of_enable_dma,
129662306a36Sopenharmony_ci	.get_max_clock = esdhc_of_get_max_clock,
129762306a36Sopenharmony_ci	.get_min_clock = esdhc_of_get_min_clock,
129862306a36Sopenharmony_ci	.adma_workaround = esdhc_of_adma_workaround,
129962306a36Sopenharmony_ci	.set_bus_width = esdhc_pltfm_set_bus_width,
130062306a36Sopenharmony_ci	.reset = esdhc_reset,
130162306a36Sopenharmony_ci	.set_uhs_signaling = esdhc_set_uhs_signaling,
130262306a36Sopenharmony_ci	.irq = esdhc_irq,
130362306a36Sopenharmony_ci};
130462306a36Sopenharmony_ci
130562306a36Sopenharmony_cistatic const struct sdhci_pltfm_data sdhci_esdhc_be_pdata = {
130662306a36Sopenharmony_ci	.quirks = ESDHC_DEFAULT_QUIRKS |
130762306a36Sopenharmony_ci#ifdef CONFIG_PPC
130862306a36Sopenharmony_ci		  SDHCI_QUIRK_BROKEN_CARD_DETECTION |
130962306a36Sopenharmony_ci#endif
131062306a36Sopenharmony_ci		  SDHCI_QUIRK_NO_CARD_NO_RESET |
131162306a36Sopenharmony_ci		  SDHCI_QUIRK_NO_ENDATTR_IN_NOPDESC,
131262306a36Sopenharmony_ci	.ops = &sdhci_esdhc_be_ops,
131362306a36Sopenharmony_ci};
131462306a36Sopenharmony_ci
131562306a36Sopenharmony_cistatic const struct sdhci_pltfm_data sdhci_esdhc_le_pdata = {
131662306a36Sopenharmony_ci	.quirks = ESDHC_DEFAULT_QUIRKS |
131762306a36Sopenharmony_ci		  SDHCI_QUIRK_NO_CARD_NO_RESET |
131862306a36Sopenharmony_ci		  SDHCI_QUIRK_NO_ENDATTR_IN_NOPDESC,
131962306a36Sopenharmony_ci	.ops = &sdhci_esdhc_le_ops,
132062306a36Sopenharmony_ci};
132162306a36Sopenharmony_ci
132262306a36Sopenharmony_cistatic struct soc_device_attribute soc_incorrect_hostver[] = {
132362306a36Sopenharmony_ci	{ .family = "QorIQ T4240", .revision = "1.0", },
132462306a36Sopenharmony_ci	{ .family = "QorIQ T4240", .revision = "2.0", },
132562306a36Sopenharmony_ci	{ /* sentinel */ }
132662306a36Sopenharmony_ci};
132762306a36Sopenharmony_ci
132862306a36Sopenharmony_cistatic struct soc_device_attribute soc_fixup_sdhc_clkdivs[] = {
132962306a36Sopenharmony_ci	{ .family = "QorIQ LX2160A", .revision = "1.0", },
133062306a36Sopenharmony_ci	{ .family = "QorIQ LX2160A", .revision = "2.0", },
133162306a36Sopenharmony_ci	{ .family = "QorIQ LS1028A", .revision = "1.0", },
133262306a36Sopenharmony_ci	{ /* sentinel */ }
133362306a36Sopenharmony_ci};
133462306a36Sopenharmony_ci
133562306a36Sopenharmony_cistatic struct soc_device_attribute soc_unreliable_pulse_detection[] = {
133662306a36Sopenharmony_ci	{ .family = "QorIQ LX2160A", .revision = "1.0", },
133762306a36Sopenharmony_ci	{ .family = "QorIQ LX2160A", .revision = "2.0", },
133862306a36Sopenharmony_ci	{ .family = "QorIQ LS1028A", .revision = "1.0", },
133962306a36Sopenharmony_ci	{ /* sentinel */ }
134062306a36Sopenharmony_ci};
134162306a36Sopenharmony_ci
134262306a36Sopenharmony_cistatic void esdhc_init(struct platform_device *pdev, struct sdhci_host *host)
134362306a36Sopenharmony_ci{
134462306a36Sopenharmony_ci	const struct of_device_id *match;
134562306a36Sopenharmony_ci	struct sdhci_pltfm_host *pltfm_host;
134662306a36Sopenharmony_ci	struct sdhci_esdhc *esdhc;
134762306a36Sopenharmony_ci	struct device_node *np;
134862306a36Sopenharmony_ci	struct clk *clk;
134962306a36Sopenharmony_ci	u32 val;
135062306a36Sopenharmony_ci	u16 host_ver;
135162306a36Sopenharmony_ci
135262306a36Sopenharmony_ci	pltfm_host = sdhci_priv(host);
135362306a36Sopenharmony_ci	esdhc = sdhci_pltfm_priv(pltfm_host);
135462306a36Sopenharmony_ci
135562306a36Sopenharmony_ci	host_ver = sdhci_readw(host, SDHCI_HOST_VERSION);
135662306a36Sopenharmony_ci	esdhc->vendor_ver = (host_ver & SDHCI_VENDOR_VER_MASK) >>
135762306a36Sopenharmony_ci			     SDHCI_VENDOR_VER_SHIFT;
135862306a36Sopenharmony_ci	esdhc->spec_ver = host_ver & SDHCI_SPEC_VER_MASK;
135962306a36Sopenharmony_ci	if (soc_device_match(soc_incorrect_hostver))
136062306a36Sopenharmony_ci		esdhc->quirk_incorrect_hostver = true;
136162306a36Sopenharmony_ci	else
136262306a36Sopenharmony_ci		esdhc->quirk_incorrect_hostver = false;
136362306a36Sopenharmony_ci
136462306a36Sopenharmony_ci	if (soc_device_match(soc_fixup_sdhc_clkdivs))
136562306a36Sopenharmony_ci		esdhc->quirk_limited_clk_division = true;
136662306a36Sopenharmony_ci	else
136762306a36Sopenharmony_ci		esdhc->quirk_limited_clk_division = false;
136862306a36Sopenharmony_ci
136962306a36Sopenharmony_ci	if (soc_device_match(soc_unreliable_pulse_detection))
137062306a36Sopenharmony_ci		esdhc->quirk_unreliable_pulse_detection = true;
137162306a36Sopenharmony_ci	else
137262306a36Sopenharmony_ci		esdhc->quirk_unreliable_pulse_detection = false;
137362306a36Sopenharmony_ci
137462306a36Sopenharmony_ci	match = of_match_node(sdhci_esdhc_of_match, pdev->dev.of_node);
137562306a36Sopenharmony_ci	if (match)
137662306a36Sopenharmony_ci		esdhc->clk_fixup = match->data;
137762306a36Sopenharmony_ci	np = pdev->dev.of_node;
137862306a36Sopenharmony_ci
137962306a36Sopenharmony_ci	if (of_device_is_compatible(np, "fsl,p2020-esdhc")) {
138062306a36Sopenharmony_ci		esdhc->quirk_delay_before_data_reset = true;
138162306a36Sopenharmony_ci		esdhc->quirk_trans_complete_erratum = true;
138262306a36Sopenharmony_ci	}
138362306a36Sopenharmony_ci
138462306a36Sopenharmony_ci	clk = of_clk_get(np, 0);
138562306a36Sopenharmony_ci	if (!IS_ERR(clk)) {
138662306a36Sopenharmony_ci		/*
138762306a36Sopenharmony_ci		 * esdhc->peripheral_clock would be assigned with a value
138862306a36Sopenharmony_ci		 * which is eSDHC base clock when use periperal clock.
138962306a36Sopenharmony_ci		 * For some platforms, the clock value got by common clk
139062306a36Sopenharmony_ci		 * API is peripheral clock while the eSDHC base clock is
139162306a36Sopenharmony_ci		 * 1/2 peripheral clock.
139262306a36Sopenharmony_ci		 */
139362306a36Sopenharmony_ci		if (of_device_is_compatible(np, "fsl,ls1046a-esdhc") ||
139462306a36Sopenharmony_ci		    of_device_is_compatible(np, "fsl,ls1028a-esdhc") ||
139562306a36Sopenharmony_ci		    of_device_is_compatible(np, "fsl,ls1088a-esdhc"))
139662306a36Sopenharmony_ci			esdhc->peripheral_clock = clk_get_rate(clk) / 2;
139762306a36Sopenharmony_ci		else
139862306a36Sopenharmony_ci			esdhc->peripheral_clock = clk_get_rate(clk);
139962306a36Sopenharmony_ci
140062306a36Sopenharmony_ci		clk_put(clk);
140162306a36Sopenharmony_ci	}
140262306a36Sopenharmony_ci
140362306a36Sopenharmony_ci	esdhc_clock_enable(host, false);
140462306a36Sopenharmony_ci	val = sdhci_readl(host, ESDHC_DMA_SYSCTL);
140562306a36Sopenharmony_ci	/*
140662306a36Sopenharmony_ci	 * This bit is not able to be reset by SDHCI_RESET_ALL. Need to
140762306a36Sopenharmony_ci	 * initialize it as 1 or 0 once, to override the different value
140862306a36Sopenharmony_ci	 * which may be configured in bootloader.
140962306a36Sopenharmony_ci	 */
141062306a36Sopenharmony_ci	if (esdhc->peripheral_clock)
141162306a36Sopenharmony_ci		val |= ESDHC_PERIPHERAL_CLK_SEL;
141262306a36Sopenharmony_ci	else
141362306a36Sopenharmony_ci		val &= ~ESDHC_PERIPHERAL_CLK_SEL;
141462306a36Sopenharmony_ci	sdhci_writel(host, val, ESDHC_DMA_SYSCTL);
141562306a36Sopenharmony_ci	esdhc_clock_enable(host, true);
141662306a36Sopenharmony_ci}
141762306a36Sopenharmony_ci
141862306a36Sopenharmony_cistatic int esdhc_hs400_prepare_ddr(struct mmc_host *mmc)
141962306a36Sopenharmony_ci{
142062306a36Sopenharmony_ci	esdhc_tuning_block_enable(mmc_priv(mmc), false);
142162306a36Sopenharmony_ci	return 0;
142262306a36Sopenharmony_ci}
142362306a36Sopenharmony_ci
142462306a36Sopenharmony_cistatic int sdhci_esdhc_probe(struct platform_device *pdev)
142562306a36Sopenharmony_ci{
142662306a36Sopenharmony_ci	struct sdhci_host *host;
142762306a36Sopenharmony_ci	struct device_node *np, *tp;
142862306a36Sopenharmony_ci	struct sdhci_pltfm_host *pltfm_host;
142962306a36Sopenharmony_ci	struct sdhci_esdhc *esdhc;
143062306a36Sopenharmony_ci	int ret;
143162306a36Sopenharmony_ci
143262306a36Sopenharmony_ci	np = pdev->dev.of_node;
143362306a36Sopenharmony_ci
143462306a36Sopenharmony_ci	if (of_property_read_bool(np, "little-endian"))
143562306a36Sopenharmony_ci		host = sdhci_pltfm_init(pdev, &sdhci_esdhc_le_pdata,
143662306a36Sopenharmony_ci					sizeof(struct sdhci_esdhc));
143762306a36Sopenharmony_ci	else
143862306a36Sopenharmony_ci		host = sdhci_pltfm_init(pdev, &sdhci_esdhc_be_pdata,
143962306a36Sopenharmony_ci					sizeof(struct sdhci_esdhc));
144062306a36Sopenharmony_ci
144162306a36Sopenharmony_ci	if (IS_ERR(host))
144262306a36Sopenharmony_ci		return PTR_ERR(host);
144362306a36Sopenharmony_ci
144462306a36Sopenharmony_ci	host->mmc_host_ops.start_signal_voltage_switch =
144562306a36Sopenharmony_ci		esdhc_signal_voltage_switch;
144662306a36Sopenharmony_ci	host->mmc_host_ops.execute_tuning = esdhc_execute_tuning;
144762306a36Sopenharmony_ci	host->mmc_host_ops.hs400_prepare_ddr = esdhc_hs400_prepare_ddr;
144862306a36Sopenharmony_ci	host->tuning_delay = 1;
144962306a36Sopenharmony_ci
145062306a36Sopenharmony_ci	esdhc_init(pdev, host);
145162306a36Sopenharmony_ci
145262306a36Sopenharmony_ci	sdhci_get_of_property(pdev);
145362306a36Sopenharmony_ci
145462306a36Sopenharmony_ci	pltfm_host = sdhci_priv(host);
145562306a36Sopenharmony_ci	esdhc = sdhci_pltfm_priv(pltfm_host);
145662306a36Sopenharmony_ci	if (soc_device_match(soc_tuning_erratum_type1))
145762306a36Sopenharmony_ci		esdhc->quirk_tuning_erratum_type1 = true;
145862306a36Sopenharmony_ci	else
145962306a36Sopenharmony_ci		esdhc->quirk_tuning_erratum_type1 = false;
146062306a36Sopenharmony_ci
146162306a36Sopenharmony_ci	if (soc_device_match(soc_tuning_erratum_type2))
146262306a36Sopenharmony_ci		esdhc->quirk_tuning_erratum_type2 = true;
146362306a36Sopenharmony_ci	else
146462306a36Sopenharmony_ci		esdhc->quirk_tuning_erratum_type2 = false;
146562306a36Sopenharmony_ci
146662306a36Sopenharmony_ci	if (esdhc->vendor_ver == VENDOR_V_22)
146762306a36Sopenharmony_ci		host->quirks2 |= SDHCI_QUIRK2_HOST_NO_CMD23;
146862306a36Sopenharmony_ci
146962306a36Sopenharmony_ci	if (esdhc->vendor_ver > VENDOR_V_22)
147062306a36Sopenharmony_ci		host->quirks &= ~SDHCI_QUIRK_NO_BUSY_IRQ;
147162306a36Sopenharmony_ci
147262306a36Sopenharmony_ci	tp = of_find_compatible_node(NULL, NULL, "fsl,p2020-esdhc");
147362306a36Sopenharmony_ci	if (tp) {
147462306a36Sopenharmony_ci		of_node_put(tp);
147562306a36Sopenharmony_ci		host->quirks |= SDHCI_QUIRK_RESET_AFTER_REQUEST;
147662306a36Sopenharmony_ci		host->quirks |= SDHCI_QUIRK_BROKEN_TIMEOUT_VAL;
147762306a36Sopenharmony_ci	}
147862306a36Sopenharmony_ci
147962306a36Sopenharmony_ci	if (of_device_is_compatible(np, "fsl,p5040-esdhc") ||
148062306a36Sopenharmony_ci	    of_device_is_compatible(np, "fsl,p5020-esdhc") ||
148162306a36Sopenharmony_ci	    of_device_is_compatible(np, "fsl,p4080-esdhc") ||
148262306a36Sopenharmony_ci	    of_device_is_compatible(np, "fsl,p1020-esdhc") ||
148362306a36Sopenharmony_ci	    of_device_is_compatible(np, "fsl,t1040-esdhc"))
148462306a36Sopenharmony_ci		host->quirks &= ~SDHCI_QUIRK_BROKEN_CARD_DETECTION;
148562306a36Sopenharmony_ci
148662306a36Sopenharmony_ci	if (of_device_is_compatible(np, "fsl,ls1021a-esdhc"))
148762306a36Sopenharmony_ci		host->quirks |= SDHCI_QUIRK_BROKEN_TIMEOUT_VAL;
148862306a36Sopenharmony_ci
148962306a36Sopenharmony_ci	esdhc->quirk_ignore_data_inhibit = false;
149062306a36Sopenharmony_ci	if (of_device_is_compatible(np, "fsl,p2020-esdhc")) {
149162306a36Sopenharmony_ci		/*
149262306a36Sopenharmony_ci		 * Freescale messed up with P2020 as it has a non-standard
149362306a36Sopenharmony_ci		 * host control register
149462306a36Sopenharmony_ci		 */
149562306a36Sopenharmony_ci		host->quirks2 |= SDHCI_QUIRK2_BROKEN_HOST_CONTROL;
149662306a36Sopenharmony_ci		esdhc->quirk_ignore_data_inhibit = true;
149762306a36Sopenharmony_ci	}
149862306a36Sopenharmony_ci
149962306a36Sopenharmony_ci	/* call to generic mmc_of_parse to support additional capabilities */
150062306a36Sopenharmony_ci	ret = mmc_of_parse(host->mmc);
150162306a36Sopenharmony_ci	if (ret)
150262306a36Sopenharmony_ci		goto err;
150362306a36Sopenharmony_ci
150462306a36Sopenharmony_ci	mmc_of_parse_voltage(host->mmc, &host->ocr_mask);
150562306a36Sopenharmony_ci
150662306a36Sopenharmony_ci	ret = sdhci_add_host(host);
150762306a36Sopenharmony_ci	if (ret)
150862306a36Sopenharmony_ci		goto err;
150962306a36Sopenharmony_ci
151062306a36Sopenharmony_ci	return 0;
151162306a36Sopenharmony_ci err:
151262306a36Sopenharmony_ci	sdhci_pltfm_free(pdev);
151362306a36Sopenharmony_ci	return ret;
151462306a36Sopenharmony_ci}
151562306a36Sopenharmony_ci
151662306a36Sopenharmony_cistatic struct platform_driver sdhci_esdhc_driver = {
151762306a36Sopenharmony_ci	.driver = {
151862306a36Sopenharmony_ci		.name = "sdhci-esdhc",
151962306a36Sopenharmony_ci		.probe_type = PROBE_PREFER_ASYNCHRONOUS,
152062306a36Sopenharmony_ci		.of_match_table = sdhci_esdhc_of_match,
152162306a36Sopenharmony_ci		.pm = &esdhc_of_dev_pm_ops,
152262306a36Sopenharmony_ci	},
152362306a36Sopenharmony_ci	.probe = sdhci_esdhc_probe,
152462306a36Sopenharmony_ci	.remove_new = sdhci_pltfm_remove,
152562306a36Sopenharmony_ci};
152662306a36Sopenharmony_ci
152762306a36Sopenharmony_cimodule_platform_driver(sdhci_esdhc_driver);
152862306a36Sopenharmony_ci
152962306a36Sopenharmony_ciMODULE_DESCRIPTION("SDHCI OF driver for Freescale MPC eSDHC");
153062306a36Sopenharmony_ciMODULE_AUTHOR("Xiaobo Xie <X.Xie@freescale.com>, "
153162306a36Sopenharmony_ci	      "Anton Vorontsov <avorontsov@ru.mvista.com>");
153262306a36Sopenharmony_ciMODULE_LICENSE("GPL v2");
1533