1a6e7e407SFabio Estevam // SPDX-License-Identifier: GPL-2.0
295f25efeSWolfram Sang /*
395f25efeSWolfram Sang  * Freescale eSDHC i.MX controller driver for the platform bus.
495f25efeSWolfram Sang  *
595f25efeSWolfram Sang  * derived from the OF-version.
695f25efeSWolfram Sang  *
795f25efeSWolfram Sang  * Copyright (c) 2010 Pengutronix e.K.
8035ff831SWolfram Sang  *   Author: Wolfram Sang <kernel@pengutronix.de>
995f25efeSWolfram Sang  */
1095f25efeSWolfram Sang 
11a8e809ecSMasahiro Yamada #include <linux/bitfield.h>
1295f25efeSWolfram Sang #include <linux/io.h>
13f581e909SHaibo Chen #include <linux/iopoll.h>
1495f25efeSWolfram Sang #include <linux/delay.h>
1595f25efeSWolfram Sang #include <linux/err.h>
1695f25efeSWolfram Sang #include <linux/clk.h>
1766506f76SShawn Guo #include <linux/module.h>
18e149860dSRichard Zhu #include <linux/slab.h>
191c4989b0SBOUGH CHEN #include <linux/pm_qos.h>
2095f25efeSWolfram Sang #include <linux/mmc/host.h>
2158ac8177SRichard Zhu #include <linux/mmc/mmc.h>
2258ac8177SRichard Zhu #include <linux/mmc/sdio.h>
23fbe5fdd1SShawn Guo #include <linux/mmc/slot-gpio.h>
24abfafc2dSShawn Guo #include <linux/of.h>
25c62da8a8SRob Herring #include <linux/platform_device.h>
26e62d8b8fSDong Aisheng #include <linux/pinctrl/consumer.h>
2789d7e5c1SDong Aisheng #include <linux/pm_runtime.h>
28fb1dec44SBrian Norris #include "sdhci-cqhci.h"
2995f25efeSWolfram Sang #include "sdhci-pltfm.h"
3095f25efeSWolfram Sang #include "sdhci-esdhc.h"
31bb6e3581SBOUGH CHEN #include "cqhci.h"
3295f25efeSWolfram Sang 
33a215186dSHaibo Chen #define ESDHC_SYS_CTRL_DTOCV_MASK	0x0f
3460bf6396SShawn Guo #define	ESDHC_CTRL_D3CD			0x08
35fd44954eSHaibo Chen #define ESDHC_BURST_LEN_EN_INCR		(1 << 27)
3658ac8177SRichard Zhu /* VENDOR SPEC register */
3760bf6396SShawn Guo #define ESDHC_VENDOR_SPEC		0xc0
3860bf6396SShawn Guo #define  ESDHC_VENDOR_SPEC_SDIO_QUIRK	(1 << 1)
390322191eSDong Aisheng #define  ESDHC_VENDOR_SPEC_VSELECT	(1 << 1)
40fed2f6e2SDong Aisheng #define  ESDHC_VENDOR_SPEC_FRC_SDCLK_ON	(1 << 8)
413722c74cSHaibo Chen #define ESDHC_DEBUG_SEL_AND_STATUS_REG		0xc2
423722c74cSHaibo Chen #define ESDHC_DEBUG_SEL_REG			0xc3
433722c74cSHaibo Chen #define ESDHC_DEBUG_SEL_MASK			0xf
443722c74cSHaibo Chen #define ESDHC_DEBUG_SEL_CMD_STATE		1
453722c74cSHaibo Chen #define ESDHC_DEBUG_SEL_DATA_STATE		2
463722c74cSHaibo Chen #define ESDHC_DEBUG_SEL_TRANS_STATE		3
473722c74cSHaibo Chen #define ESDHC_DEBUG_SEL_DMA_STATE		4
483722c74cSHaibo Chen #define ESDHC_DEBUG_SEL_ADMA_STATE		5
493722c74cSHaibo Chen #define ESDHC_DEBUG_SEL_FIFO_STATE		6
503722c74cSHaibo Chen #define ESDHC_DEBUG_SEL_ASYNC_FIFO_STATE	7
5160bf6396SShawn Guo #define ESDHC_WTMK_LVL			0x44
52cc17e129SDong Aisheng #define  ESDHC_WTMK_DEFAULT_VAL		0x10401040
533fbd4322SAndrew Gabbasov #define  ESDHC_WTMK_LVL_RD_WML_MASK	0x000000FF
543fbd4322SAndrew Gabbasov #define  ESDHC_WTMK_LVL_RD_WML_SHIFT	0
553fbd4322SAndrew Gabbasov #define  ESDHC_WTMK_LVL_WR_WML_MASK	0x00FF0000
563fbd4322SAndrew Gabbasov #define  ESDHC_WTMK_LVL_WR_WML_SHIFT	16
573fbd4322SAndrew Gabbasov #define  ESDHC_WTMK_LVL_WML_VAL_DEF	64
583fbd4322SAndrew Gabbasov #define  ESDHC_WTMK_LVL_WML_VAL_MAX	128
5960bf6396SShawn Guo #define ESDHC_MIX_CTRL			0x48
60de5bdbffSDong Aisheng #define  ESDHC_MIX_CTRL_DDREN		(1 << 3)
612a15f981SShawn Guo #define  ESDHC_MIX_CTRL_AC23EN		(1 << 7)
620322191eSDong Aisheng #define  ESDHC_MIX_CTRL_EXE_TUNE	(1 << 22)
630322191eSDong Aisheng #define  ESDHC_MIX_CTRL_SMPCLK_SEL	(1 << 23)
640b330e38SDong Aisheng #define  ESDHC_MIX_CTRL_AUTO_TUNE_EN	(1 << 24)
650322191eSDong Aisheng #define  ESDHC_MIX_CTRL_FBCLK_SEL	(1 << 25)
6628b07674SHaibo Chen #define  ESDHC_MIX_CTRL_HS400_EN	(1 << 26)
67029e2476SBOUGH CHEN #define  ESDHC_MIX_CTRL_HS400_ES_EN	(1 << 27)
682a15f981SShawn Guo /* Bits 3 and 6 are not SDHCI standard definitions */
692a15f981SShawn Guo #define  ESDHC_MIX_CTRL_SDHCI_MASK	0xb7
70d131a71cSDong Aisheng /* Tuning bits */
71d131a71cSDong Aisheng #define  ESDHC_MIX_CTRL_TUNING_MASK	0x03c00000
7258ac8177SRichard Zhu 
73602519b2SDong Aisheng /* dll control register */
74602519b2SDong Aisheng #define ESDHC_DLL_CTRL			0x60
75602519b2SDong Aisheng #define ESDHC_DLL_OVERRIDE_VAL_SHIFT	9
76602519b2SDong Aisheng #define ESDHC_DLL_OVERRIDE_EN_SHIFT	8
77602519b2SDong Aisheng 
780322191eSDong Aisheng /* tune control register */
790322191eSDong Aisheng #define ESDHC_TUNE_CTRL_STATUS		0x68
800322191eSDong Aisheng #define  ESDHC_TUNE_CTRL_STEP		1
810322191eSDong Aisheng #define  ESDHC_TUNE_CTRL_MIN		0
820322191eSDong Aisheng #define  ESDHC_TUNE_CTRL_MAX		((1 << 7) - 1)
830322191eSDong Aisheng 
8428b07674SHaibo Chen /* strobe dll register */
8528b07674SHaibo Chen #define ESDHC_STROBE_DLL_CTRL		0x70
8628b07674SHaibo Chen #define ESDHC_STROBE_DLL_CTRL_ENABLE	(1 << 0)
8728b07674SHaibo Chen #define ESDHC_STROBE_DLL_CTRL_RESET	(1 << 1)
885bd2acdcSHaibo Chen #define ESDHC_STROBE_DLL_CTRL_SLV_DLY_TARGET_DEFAULT	0x7
8928b07674SHaibo Chen #define ESDHC_STROBE_DLL_CTRL_SLV_DLY_TARGET_SHIFT	3
902eaf5a53SBOUGH CHEN #define ESDHC_STROBE_DLL_CTRL_SLV_UPDATE_INT_DEFAULT	(4 << 20)
9128b07674SHaibo Chen 
9228b07674SHaibo Chen #define ESDHC_STROBE_DLL_STATUS		0x74
9328b07674SHaibo Chen #define ESDHC_STROBE_DLL_STS_REF_LOCK	(1 << 1)
9428b07674SHaibo Chen #define ESDHC_STROBE_DLL_STS_SLV_LOCK	0x1
9528b07674SHaibo Chen 
96bcdb5301SBOUGH CHEN #define ESDHC_VEND_SPEC2		0xc8
97bcdb5301SBOUGH CHEN #define ESDHC_VEND_SPEC2_EN_BUSY_IRQ	(1 << 8)
9845334ee1SHaibo Chen #define ESDHC_VEND_SPEC2_AUTO_TUNE_8BIT_EN	(1 << 4)
9945334ee1SHaibo Chen #define ESDHC_VEND_SPEC2_AUTO_TUNE_4BIT_EN	(0 << 4)
10045334ee1SHaibo Chen #define ESDHC_VEND_SPEC2_AUTO_TUNE_1BIT_EN	(2 << 4)
10145334ee1SHaibo Chen #define ESDHC_VEND_SPEC2_AUTO_TUNE_CMD_EN	(1 << 6)
10245334ee1SHaibo Chen #define ESDHC_VEND_SPEC2_AUTO_TUNE_MODE_MASK	(7 << 4)
103bcdb5301SBOUGH CHEN 
1046e9fd28eSDong Aisheng #define ESDHC_TUNING_CTRL		0xcc
1056e9fd28eSDong Aisheng #define ESDHC_STD_TUNING_EN		(1 << 24)
1066e9fd28eSDong Aisheng /* NOTE: the minimum valid tuning start tap for mx6sl is 1 */
107d87fc966SDong Aisheng #define ESDHC_TUNING_START_TAP_DEFAULT	0x1
1081194be8cSHaibo Chen #define ESDHC_TUNING_START_TAP_MASK	0x7f
10916e40e5bSHaibo Chen #define ESDHC_TUNING_CMD_CRC_CHECK_DISABLE	(1 << 7)
1101e336aa0SHaibo Chen #define ESDHC_TUNING_STEP_DEFAULT	0x1
111260ecb3cSHaibo Chen #define ESDHC_TUNING_STEP_MASK		0x00070000
112d407e30bSHaibo Chen #define ESDHC_TUNING_STEP_SHIFT		16
1136e9fd28eSDong Aisheng 
114ad93220dSDong Aisheng /* pinctrl state */
115ad93220dSDong Aisheng #define ESDHC_PINCTRL_STATE_100MHZ	"state_100mhz"
116ad93220dSDong Aisheng #define ESDHC_PINCTRL_STATE_200MHZ	"state_200mhz"
117ad93220dSDong Aisheng 
11858ac8177SRichard Zhu /*
119af51079eSSascha Hauer  * Our interpretation of the SDHCI_HOST_CONTROL register
120af51079eSSascha Hauer  */
121af51079eSSascha Hauer #define ESDHC_CTRL_4BITBUS		(0x1 << 1)
122af51079eSSascha Hauer #define ESDHC_CTRL_8BITBUS		(0x2 << 1)
123af51079eSSascha Hauer #define ESDHC_CTRL_BUSWIDTH_MASK	(0x3 << 1)
12445334ee1SHaibo Chen #define USDHC_GET_BUSWIDTH(c) (c & ESDHC_CTRL_BUSWIDTH_MASK)
125af51079eSSascha Hauer 
126af51079eSSascha Hauer /*
127d04f8d5bSBenoît Thébaudeau  * There is an INT DMA ERR mismatch between eSDHC and STD SDHC SPEC:
12897e4ba6aSRichard Zhu  * Bit25 is used in STD SPEC, and is reserved in fsl eSDHC design,
12997e4ba6aSRichard Zhu  * but bit28 is used as the INT DMA ERR in fsl eSDHC design.
13097e4ba6aSRichard Zhu  * Define this macro DMA error INT for fsl eSDHC
13197e4ba6aSRichard Zhu  */
13260bf6396SShawn Guo #define ESDHC_INT_VENDOR_SPEC_DMA_ERR	(1 << 28)
13397e4ba6aSRichard Zhu 
134bb6e3581SBOUGH CHEN /* the address offset of CQHCI */
135bb6e3581SBOUGH CHEN #define ESDHC_CQHCI_ADDR_OFFSET		0x100
136bb6e3581SBOUGH CHEN 
13797e4ba6aSRichard Zhu /*
13858ac8177SRichard Zhu  * The CMDTYPE of the CMD register (offset 0xE) should be set to
13958ac8177SRichard Zhu  * "11" when the STOP CMD12 is issued on imx53 to abort one
14058ac8177SRichard Zhu  * open ended multi-blk IO. Otherwise the TC INT wouldn't
14158ac8177SRichard Zhu  * be generated.
14258ac8177SRichard Zhu  * In exact block transfer, the controller doesn't complete the
14358ac8177SRichard Zhu  * operations automatically as required at the end of the
14458ac8177SRichard Zhu  * transfer and remains on hold if the abort command is not sent.
14558ac8177SRichard Zhu  * As a result, the TC flag is not asserted and SW received timeout
146d04f8d5bSBenoît Thébaudeau  * exception. Bit1 of Vendor Spec register is used to fix it.
14758ac8177SRichard Zhu  */
14831fbb301SShawn Guo #define ESDHC_FLAG_MULTIBLK_NO_INT	BIT(1)
14931fbb301SShawn Guo /*
1509d61c009SShawn Guo  * The flag tells that the ESDHC controller is an USDHC block that is
1519d61c009SShawn Guo  * integrated on the i.MX6 series.
1529d61c009SShawn Guo  */
1539d61c009SShawn Guo #define ESDHC_FLAG_USDHC		BIT(3)
1546e9fd28eSDong Aisheng /* The IP supports manual tuning process */
1556e9fd28eSDong Aisheng #define ESDHC_FLAG_MAN_TUNING		BIT(4)
1566e9fd28eSDong Aisheng /* The IP supports standard tuning process */
1576e9fd28eSDong Aisheng #define ESDHC_FLAG_STD_TUNING		BIT(5)
1586e9fd28eSDong Aisheng /* The IP has SDHCI_CAPABILITIES_1 register */
1596e9fd28eSDong Aisheng #define ESDHC_FLAG_HAVE_CAP1		BIT(6)
16018094430SDong Aisheng /*
161d04f8d5bSBenoît Thébaudeau  * The IP has erratum ERR004536
16218094430SDong Aisheng  * uSDHC: ADMA Length Mismatch Error occurs if the AHB read access is slow,
16318094430SDong Aisheng  * when reading data from the card
164667123f6SBenoît Thébaudeau  * This flag is also set for i.MX25 and i.MX35 in order to get
165667123f6SBenoît Thébaudeau  * SDHCI_QUIRK_BROKEN_ADMA, but for different reasons (ADMA capability bits).
16618094430SDong Aisheng  */
16718094430SDong Aisheng #define ESDHC_FLAG_ERR004536		BIT(7)
1684245afffSDong Aisheng /* The IP supports HS200 mode */
1694245afffSDong Aisheng #define ESDHC_FLAG_HS200		BIT(8)
17028b07674SHaibo Chen /* The IP supports HS400 mode */
17128b07674SHaibo Chen #define ESDHC_FLAG_HS400		BIT(9)
172af6a50d4SBOUGH CHEN /*
173af6a50d4SBOUGH CHEN  * The IP has errata ERR010450
174*5ae4b0d8SGiulio Benetti  * uSDHC: At 1.8V due to the I/O timing limit, for SDR mode, SD card
175*5ae4b0d8SGiulio Benetti  * clock can't exceed 150MHz, for DDR mode, SD card clock can't exceed 45MHz.
176af6a50d4SBOUGH CHEN  */
177af6a50d4SBOUGH CHEN #define ESDHC_FLAG_ERR010450		BIT(10)
178029e2476SBOUGH CHEN /* The IP supports HS400ES mode */
179029e2476SBOUGH CHEN #define ESDHC_FLAG_HS400_ES		BIT(11)
180bb6e3581SBOUGH CHEN /* The IP has Host Controller Interface for Command Queuing */
181bb6e3581SBOUGH CHEN #define ESDHC_FLAG_CQHCI		BIT(12)
1821c4989b0SBOUGH CHEN /* need request pmqos during low power */
1831c4989b0SBOUGH CHEN #define ESDHC_FLAG_PMQOS		BIT(13)
184a26a4f1bSHaibo Chen /* The IP state got lost in low power mode */
185a26a4f1bSHaibo Chen #define ESDHC_FLAG_STATE_LOST_IN_LPMODE		BIT(14)
1865c11f1ffSHaibo Chen /* The IP lost clock rate in PM_RUNTIME */
1875c11f1ffSHaibo Chen #define ESDHC_FLAG_CLK_RATE_LOST_IN_PM_RUNTIME	BIT(15)
18874898cbcSHaibo Chen /*
18974898cbcSHaibo Chen  * The IP do not support the ACMD23 feature completely when use ADMA mode.
19074898cbcSHaibo Chen  * In ADMA mode, it only use the 16 bit block count of the register 0x4
19174898cbcSHaibo Chen  * (BLOCK_ATT) as the CMD23's argument for ACMD23 mode, which means it will
19274898cbcSHaibo Chen  * ignore the upper 16 bit of the CMD23's argument. This will block the reliable
19374898cbcSHaibo Chen  * write operation in RPMB, because RPMB reliable write need to set the bit31
19474898cbcSHaibo Chen  * of the CMD23's argument.
19574898cbcSHaibo Chen  * imx6qpdl/imx6sx/imx6sl/imx7d has this limitation only for ADMA mode, SDMA
19674898cbcSHaibo Chen  * do not has this limitation. so when these SoC use ADMA mode, it need to
19774898cbcSHaibo Chen  * disable the ACMD23 feature.
19874898cbcSHaibo Chen  */
19974898cbcSHaibo Chen #define ESDHC_FLAG_BROKEN_AUTO_CMD23	BIT(16)
200e149860dSRichard Zhu 
2015c4f0062SChester Lin /* ERR004536 is not applicable for the IP  */
2025c4f0062SChester Lin #define ESDHC_FLAG_SKIP_ERR004536	BIT(17)
2035c4f0062SChester Lin 
2044a11cc64SFabio Estevam enum wp_types {
2054a11cc64SFabio Estevam 	ESDHC_WP_NONE,		/* no WP, neither controller nor gpio */
2064a11cc64SFabio Estevam 	ESDHC_WP_CONTROLLER,	/* mmc controller internal WP */
2074a11cc64SFabio Estevam 	ESDHC_WP_GPIO,		/* external gpio pin for WP */
2084a11cc64SFabio Estevam };
2094a11cc64SFabio Estevam 
2104a11cc64SFabio Estevam enum cd_types {
2114a11cc64SFabio Estevam 	ESDHC_CD_NONE,		/* no CD, neither controller nor gpio */
2124a11cc64SFabio Estevam 	ESDHC_CD_CONTROLLER,	/* mmc controller internal CD */
2134a11cc64SFabio Estevam 	ESDHC_CD_GPIO,		/* external gpio pin for CD */
2144a11cc64SFabio Estevam 	ESDHC_CD_PERMANENT,	/* no CD, card permanently wired to host */
2154a11cc64SFabio Estevam };
2164a11cc64SFabio Estevam 
2174a11cc64SFabio Estevam /*
2184a11cc64SFabio Estevam  * struct esdhc_platform_data - platform data for esdhc on i.MX
2194a11cc64SFabio Estevam  *
2204a11cc64SFabio Estevam  * ESDHC_WP(CD)_CONTROLLER type is not available on i.MX25/35.
2214a11cc64SFabio Estevam  *
2224a11cc64SFabio Estevam  * @wp_type:	type of write_protect method (see wp_types enum above)
2234a11cc64SFabio Estevam  * @cd_type:	type of card_detect method (see cd_types enum above)
2244a11cc64SFabio Estevam  */
2254a11cc64SFabio Estevam 
2264a11cc64SFabio Estevam struct esdhc_platform_data {
2274a11cc64SFabio Estevam 	enum wp_types wp_type;
2284a11cc64SFabio Estevam 	enum cd_types cd_type;
2294a11cc64SFabio Estevam 	int max_bus_width;
2304a11cc64SFabio Estevam 	unsigned int delay_line;
2314a11cc64SFabio Estevam 	unsigned int tuning_step;       /* The delay cell steps in tuning procedure */
2324a11cc64SFabio Estevam 	unsigned int tuning_start_tap;	/* The start delay cell point in tuning procedure */
2334a11cc64SFabio Estevam 	unsigned int strobe_dll_delay_target;	/* The delay cell for strobe pad (read clock) */
2344a11cc64SFabio Estevam };
2354a11cc64SFabio Estevam 
236f47c4bbfSShawn Guo struct esdhc_soc_data {
237f47c4bbfSShawn Guo 	u32 flags;
238f47c4bbfSShawn Guo };
239f47c4bbfSShawn Guo 
2404f100012SAndrey Smirnov static const struct esdhc_soc_data esdhc_imx25_data = {
241667123f6SBenoît Thébaudeau 	.flags = ESDHC_FLAG_ERR004536,
242f47c4bbfSShawn Guo };
243f47c4bbfSShawn Guo 
2444f100012SAndrey Smirnov static const struct esdhc_soc_data esdhc_imx35_data = {
245667123f6SBenoît Thébaudeau 	.flags = ESDHC_FLAG_ERR004536,
246f47c4bbfSShawn Guo };
247f47c4bbfSShawn Guo 
2484f100012SAndrey Smirnov static const struct esdhc_soc_data esdhc_imx51_data = {
249f47c4bbfSShawn Guo 	.flags = 0,
250f47c4bbfSShawn Guo };
251f47c4bbfSShawn Guo 
2524f100012SAndrey Smirnov static const struct esdhc_soc_data esdhc_imx53_data = {
253f47c4bbfSShawn Guo 	.flags = ESDHC_FLAG_MULTIBLK_NO_INT,
254f47c4bbfSShawn Guo };
255f47c4bbfSShawn Guo 
2564f100012SAndrey Smirnov static const struct esdhc_soc_data usdhc_imx6q_data = {
25774898cbcSHaibo Chen 	.flags = ESDHC_FLAG_USDHC | ESDHC_FLAG_MAN_TUNING
25874898cbcSHaibo Chen 			| ESDHC_FLAG_BROKEN_AUTO_CMD23,
2596e9fd28eSDong Aisheng };
2606e9fd28eSDong Aisheng 
2614f100012SAndrey Smirnov static const struct esdhc_soc_data usdhc_imx6sl_data = {
2626e9fd28eSDong Aisheng 	.flags = ESDHC_FLAG_USDHC | ESDHC_FLAG_STD_TUNING
2634245afffSDong Aisheng 			| ESDHC_FLAG_HAVE_CAP1 | ESDHC_FLAG_ERR004536
26474898cbcSHaibo Chen 			| ESDHC_FLAG_HS200
26574898cbcSHaibo Chen 			| ESDHC_FLAG_BROKEN_AUTO_CMD23,
26674898cbcSHaibo Chen };
26774898cbcSHaibo Chen 
26874898cbcSHaibo Chen static const struct esdhc_soc_data usdhc_imx6sll_data = {
26974898cbcSHaibo Chen 	.flags = ESDHC_FLAG_USDHC | ESDHC_FLAG_STD_TUNING
27074898cbcSHaibo Chen 			| ESDHC_FLAG_HAVE_CAP1 | ESDHC_FLAG_HS200
27186b59671SHaibo Chen 			| ESDHC_FLAG_HS400
27274898cbcSHaibo Chen 			| ESDHC_FLAG_STATE_LOST_IN_LPMODE,
27357ed3314SShawn Guo };
27457ed3314SShawn Guo 
2754f100012SAndrey Smirnov static const struct esdhc_soc_data usdhc_imx6sx_data = {
276913d4951SDong Aisheng 	.flags = ESDHC_FLAG_USDHC | ESDHC_FLAG_STD_TUNING
277a26a4f1bSHaibo Chen 			| ESDHC_FLAG_HAVE_CAP1 | ESDHC_FLAG_HS200
27874898cbcSHaibo Chen 			| ESDHC_FLAG_STATE_LOST_IN_LPMODE
27974898cbcSHaibo Chen 			| ESDHC_FLAG_BROKEN_AUTO_CMD23,
280913d4951SDong Aisheng };
281913d4951SDong Aisheng 
282af6a50d4SBOUGH CHEN static const struct esdhc_soc_data usdhc_imx6ull_data = {
283af6a50d4SBOUGH CHEN 	.flags = ESDHC_FLAG_USDHC | ESDHC_FLAG_STD_TUNING
284af6a50d4SBOUGH CHEN 			| ESDHC_FLAG_HAVE_CAP1 | ESDHC_FLAG_HS200
285a26a4f1bSHaibo Chen 			| ESDHC_FLAG_ERR010450
286a26a4f1bSHaibo Chen 			| ESDHC_FLAG_STATE_LOST_IN_LPMODE,
287af6a50d4SBOUGH CHEN };
288af6a50d4SBOUGH CHEN 
2894f100012SAndrey Smirnov static const struct esdhc_soc_data usdhc_imx7d_data = {
29028b07674SHaibo Chen 	.flags = ESDHC_FLAG_USDHC | ESDHC_FLAG_STD_TUNING
29128b07674SHaibo Chen 			| ESDHC_FLAG_HAVE_CAP1 | ESDHC_FLAG_HS200
292a26a4f1bSHaibo Chen 			| ESDHC_FLAG_HS400
29374898cbcSHaibo Chen 			| ESDHC_FLAG_STATE_LOST_IN_LPMODE
29474898cbcSHaibo Chen 			| ESDHC_FLAG_BROKEN_AUTO_CMD23,
29528b07674SHaibo Chen };
29628b07674SHaibo Chen 
2975c4f0062SChester Lin static struct esdhc_soc_data usdhc_s32g2_data = {
2985c4f0062SChester Lin 	.flags = ESDHC_FLAG_USDHC | ESDHC_FLAG_MAN_TUNING
2995c4f0062SChester Lin 			| ESDHC_FLAG_HAVE_CAP1 | ESDHC_FLAG_HS200
3005c4f0062SChester Lin 			| ESDHC_FLAG_HS400 | ESDHC_FLAG_HS400_ES
3015c4f0062SChester Lin 			| ESDHC_FLAG_SKIP_ERR004536,
3025c4f0062SChester Lin };
3035c4f0062SChester Lin 
3041c4989b0SBOUGH CHEN static struct esdhc_soc_data usdhc_imx7ulp_data = {
3051c4989b0SBOUGH CHEN 	.flags = ESDHC_FLAG_USDHC | ESDHC_FLAG_STD_TUNING
3061c4989b0SBOUGH CHEN 			| ESDHC_FLAG_HAVE_CAP1 | ESDHC_FLAG_HS200
307a26a4f1bSHaibo Chen 			| ESDHC_FLAG_PMQOS | ESDHC_FLAG_HS400
308a26a4f1bSHaibo Chen 			| ESDHC_FLAG_STATE_LOST_IN_LPMODE,
3091c4989b0SBOUGH CHEN };
3102f4788f3SJesse Taube static struct esdhc_soc_data usdhc_imxrt1050_data = {
311d7a1830eSGiulio Benetti 	.flags = ESDHC_FLAG_USDHC | ESDHC_FLAG_STD_TUNING
312d7a1830eSGiulio Benetti 			| ESDHC_FLAG_HAVE_CAP1 | ESDHC_FLAG_HS200,
3132f4788f3SJesse Taube };
3141c4989b0SBOUGH CHEN 
315029e2476SBOUGH CHEN static struct esdhc_soc_data usdhc_imx8qxp_data = {
316029e2476SBOUGH CHEN 	.flags = ESDHC_FLAG_USDHC | ESDHC_FLAG_STD_TUNING
317029e2476SBOUGH CHEN 			| ESDHC_FLAG_HAVE_CAP1 | ESDHC_FLAG_HS200
318bb6e3581SBOUGH CHEN 			| ESDHC_FLAG_HS400 | ESDHC_FLAG_HS400_ES
3195c11f1ffSHaibo Chen 			| ESDHC_FLAG_STATE_LOST_IN_LPMODE
3205c11f1ffSHaibo Chen 			| ESDHC_FLAG_CLK_RATE_LOST_IN_PM_RUNTIME,
321029e2476SBOUGH CHEN };
322029e2476SBOUGH CHEN 
323cde5e8e9SHaibo Chen static struct esdhc_soc_data usdhc_imx8mm_data = {
324cde5e8e9SHaibo Chen 	.flags = ESDHC_FLAG_USDHC | ESDHC_FLAG_STD_TUNING
325cde5e8e9SHaibo Chen 			| ESDHC_FLAG_HAVE_CAP1 | ESDHC_FLAG_HS200
326cde5e8e9SHaibo Chen 			| ESDHC_FLAG_HS400 | ESDHC_FLAG_HS400_ES
327cde5e8e9SHaibo Chen 			| ESDHC_FLAG_STATE_LOST_IN_LPMODE,
328e149860dSRichard Zhu };
329e149860dSRichard Zhu 
330e149860dSRichard Zhu struct pltfm_imx_data {
331e149860dSRichard Zhu 	u32 scratchpad;
332e62d8b8fSDong Aisheng 	struct pinctrl *pinctrl;
333ad93220dSDong Aisheng 	struct pinctrl_state *pins_100mhz;
334ad93220dSDong Aisheng 	struct pinctrl_state *pins_200mhz;
335f47c4bbfSShawn Guo 	const struct esdhc_soc_data *socdata;
336842afc02SShawn Guo 	struct esdhc_platform_data boarddata;
33752dac615SSascha Hauer 	struct clk *clk_ipg;
33852dac615SSascha Hauer 	struct clk *clk_ahb;
33952dac615SSascha Hauer 	struct clk *clk_per;
3403602785bSMichael Trimarchi 	unsigned int actual_clock;
34152e4c32bSHaibo Chen 
34252e4c32bSHaibo Chen 	/*
34352e4c32bSHaibo Chen 	 * USDHC has one limition, require the SDIO device a different
34452e4c32bSHaibo Chen 	 * register setting. Driver has to recognize card type during
34552e4c32bSHaibo Chen 	 * the card init, but at this stage, mmc_host->card is not
34652e4c32bSHaibo Chen 	 * available. So involve this field to save the card type
34752e4c32bSHaibo Chen 	 * during card init through usdhc_init_card().
34852e4c32bSHaibo Chen 	 */
34952e4c32bSHaibo Chen 	unsigned int init_card_type;
35052e4c32bSHaibo Chen 
351361b8482SLucas Stach 	enum {
352361b8482SLucas Stach 		NO_CMD_PENDING,      /* no multiblock command pending */
353361b8482SLucas Stach 		MULTIBLK_IN_PROCESS, /* exact multiblock cmd in process */
354361b8482SLucas Stach 		WAIT_FOR_INT,        /* sent CMD12, waiting for response INT */
355361b8482SLucas Stach 	} multiblock_status;
356de5bdbffSDong Aisheng 	u32 is_ddr;
3571c4989b0SBOUGH CHEN 	struct pm_qos_request pm_qos_req;
358e149860dSRichard Zhu };
359e149860dSRichard Zhu 
360abfafc2dSShawn Guo static const struct of_device_id imx_esdhc_dt_ids[] = {
361f47c4bbfSShawn Guo 	{ .compatible = "fsl,imx25-esdhc", .data = &esdhc_imx25_data, },
362f47c4bbfSShawn Guo 	{ .compatible = "fsl,imx35-esdhc", .data = &esdhc_imx35_data, },
363f47c4bbfSShawn Guo 	{ .compatible = "fsl,imx51-esdhc", .data = &esdhc_imx51_data, },
364f47c4bbfSShawn Guo 	{ .compatible = "fsl,imx53-esdhc", .data = &esdhc_imx53_data, },
365913d4951SDong Aisheng 	{ .compatible = "fsl,imx6sx-usdhc", .data = &usdhc_imx6sx_data, },
3666e9fd28eSDong Aisheng 	{ .compatible = "fsl,imx6sl-usdhc", .data = &usdhc_imx6sl_data, },
36774898cbcSHaibo Chen 	{ .compatible = "fsl,imx6sll-usdhc", .data = &usdhc_imx6sll_data, },
368f47c4bbfSShawn Guo 	{ .compatible = "fsl,imx6q-usdhc", .data = &usdhc_imx6q_data, },
369af6a50d4SBOUGH CHEN 	{ .compatible = "fsl,imx6ull-usdhc", .data = &usdhc_imx6ull_data, },
37028b07674SHaibo Chen 	{ .compatible = "fsl,imx7d-usdhc", .data = &usdhc_imx7d_data, },
3711c4989b0SBOUGH CHEN 	{ .compatible = "fsl,imx7ulp-usdhc", .data = &usdhc_imx7ulp_data, },
372029e2476SBOUGH CHEN 	{ .compatible = "fsl,imx8qxp-usdhc", .data = &usdhc_imx8qxp_data, },
373cde5e8e9SHaibo Chen 	{ .compatible = "fsl,imx8mm-usdhc", .data = &usdhc_imx8mm_data, },
3742f4788f3SJesse Taube 	{ .compatible = "fsl,imxrt1050-usdhc", .data = &usdhc_imxrt1050_data, },
3755c4f0062SChester Lin 	{ .compatible = "nxp,s32g2-usdhc", .data = &usdhc_s32g2_data, },
376abfafc2dSShawn Guo 	{ /* sentinel */ }
377abfafc2dSShawn Guo };
378abfafc2dSShawn Guo MODULE_DEVICE_TABLE(of, imx_esdhc_dt_ids);
379abfafc2dSShawn Guo 
is_imx25_esdhc(struct pltfm_imx_data * data)38057ed3314SShawn Guo static inline int is_imx25_esdhc(struct pltfm_imx_data *data)
38157ed3314SShawn Guo {
382f47c4bbfSShawn Guo 	return data->socdata == &esdhc_imx25_data;
38357ed3314SShawn Guo }
38457ed3314SShawn Guo 
is_imx53_esdhc(struct pltfm_imx_data * data)38557ed3314SShawn Guo static inline int is_imx53_esdhc(struct pltfm_imx_data *data)
38657ed3314SShawn Guo {
387f47c4bbfSShawn Guo 	return data->socdata == &esdhc_imx53_data;
38857ed3314SShawn Guo }
38957ed3314SShawn Guo 
esdhc_is_usdhc(struct pltfm_imx_data * data)3909d61c009SShawn Guo static inline int esdhc_is_usdhc(struct pltfm_imx_data *data)
3919d61c009SShawn Guo {
392f47c4bbfSShawn Guo 	return !!(data->socdata->flags & ESDHC_FLAG_USDHC);
3939d61c009SShawn Guo }
3949d61c009SShawn Guo 
esdhc_clrset_le(struct sdhci_host * host,u32 mask,u32 val,int reg)39595f25efeSWolfram Sang static inline void esdhc_clrset_le(struct sdhci_host *host, u32 mask, u32 val, int reg)
39695f25efeSWolfram Sang {
39795f25efeSWolfram Sang 	void __iomem *base = host->ioaddr + (reg & ~0x3);
39895f25efeSWolfram Sang 	u32 shift = (reg & 0x3) * 8;
39995f25efeSWolfram Sang 
40095f25efeSWolfram Sang 	writel(((readl(base) & ~(mask << shift)) | (val << shift)), base);
40195f25efeSWolfram Sang }
40295f25efeSWolfram Sang 
4033722c74cSHaibo Chen #define DRIVER_NAME "sdhci-esdhc-imx"
4043722c74cSHaibo Chen #define ESDHC_IMX_DUMP(f, x...) \
4053722c74cSHaibo Chen 	pr_err("%s: " DRIVER_NAME ": " f, mmc_hostname(host->mmc), ## x)
esdhc_dump_debug_regs(struct sdhci_host * host)4063722c74cSHaibo Chen static void esdhc_dump_debug_regs(struct sdhci_host *host)
4073722c74cSHaibo Chen {
4083722c74cSHaibo Chen 	int i;
4093722c74cSHaibo Chen 	char *debug_status[7] = {
4103722c74cSHaibo Chen 				 "cmd debug status",
4113722c74cSHaibo Chen 				 "data debug status",
4123722c74cSHaibo Chen 				 "trans debug status",
4133722c74cSHaibo Chen 				 "dma debug status",
4143722c74cSHaibo Chen 				 "adma debug status",
4153722c74cSHaibo Chen 				 "fifo debug status",
4163722c74cSHaibo Chen 				 "async fifo debug status"
4173722c74cSHaibo Chen 	};
4183722c74cSHaibo Chen 
4193722c74cSHaibo Chen 	ESDHC_IMX_DUMP("========= ESDHC IMX DEBUG STATUS DUMP =========\n");
4203722c74cSHaibo Chen 	for (i = 0; i < 7; i++) {
4213722c74cSHaibo Chen 		esdhc_clrset_le(host, ESDHC_DEBUG_SEL_MASK,
4223722c74cSHaibo Chen 			ESDHC_DEBUG_SEL_CMD_STATE + i, ESDHC_DEBUG_SEL_REG);
4233722c74cSHaibo Chen 		ESDHC_IMX_DUMP("%s:  0x%04x\n", debug_status[i],
4243722c74cSHaibo Chen 			readw(host->ioaddr + ESDHC_DEBUG_SEL_AND_STATUS_REG));
4253722c74cSHaibo Chen 	}
4263722c74cSHaibo Chen 
4273722c74cSHaibo Chen 	esdhc_clrset_le(host, ESDHC_DEBUG_SEL_MASK, 0, ESDHC_DEBUG_SEL_REG);
4283722c74cSHaibo Chen 
4293722c74cSHaibo Chen }
4303722c74cSHaibo Chen 
esdhc_wait_for_card_clock_gate_off(struct sdhci_host * host)431f581e909SHaibo Chen static inline void esdhc_wait_for_card_clock_gate_off(struct sdhci_host *host)
432f581e909SHaibo Chen {
433f581e909SHaibo Chen 	u32 present_state;
434f581e909SHaibo Chen 	int ret;
435f581e909SHaibo Chen 
436f581e909SHaibo Chen 	ret = readl_poll_timeout(host->ioaddr + ESDHC_PRSSTAT, present_state,
437f581e909SHaibo Chen 				(present_state & ESDHC_CLOCK_GATE_OFF), 2, 100);
438f581e909SHaibo Chen 	if (ret == -ETIMEDOUT)
439f581e909SHaibo Chen 		dev_warn(mmc_dev(host->mmc), "%s: card clock still not gate off in 100us!.\n", __func__);
440f581e909SHaibo Chen }
441f581e909SHaibo Chen 
44245334ee1SHaibo Chen /* Enable the auto tuning circuit to check the CMD line and BUS line */
usdhc_auto_tuning_mode_sel_and_en(struct sdhci_host * host)443c8c49a5aSHaibo Chen static inline void usdhc_auto_tuning_mode_sel_and_en(struct sdhci_host *host)
44445334ee1SHaibo Chen {
44552e4c32bSHaibo Chen 	struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
44652e4c32bSHaibo Chen 	struct pltfm_imx_data *imx_data = sdhci_pltfm_priv(pltfm_host);
44745334ee1SHaibo Chen 	u32 buswidth, auto_tune_buswidth;
448c8c49a5aSHaibo Chen 	u32 reg;
44945334ee1SHaibo Chen 
45045334ee1SHaibo Chen 	buswidth = USDHC_GET_BUSWIDTH(readl(host->ioaddr + SDHCI_HOST_CONTROL));
45145334ee1SHaibo Chen 
45245334ee1SHaibo Chen 	switch (buswidth) {
45345334ee1SHaibo Chen 	case ESDHC_CTRL_8BITBUS:
45445334ee1SHaibo Chen 		auto_tune_buswidth = ESDHC_VEND_SPEC2_AUTO_TUNE_8BIT_EN;
45545334ee1SHaibo Chen 		break;
45645334ee1SHaibo Chen 	case ESDHC_CTRL_4BITBUS:
45745334ee1SHaibo Chen 		auto_tune_buswidth = ESDHC_VEND_SPEC2_AUTO_TUNE_4BIT_EN;
45845334ee1SHaibo Chen 		break;
45945334ee1SHaibo Chen 	default:	/* 1BITBUS */
46045334ee1SHaibo Chen 		auto_tune_buswidth = ESDHC_VEND_SPEC2_AUTO_TUNE_1BIT_EN;
46145334ee1SHaibo Chen 		break;
46245334ee1SHaibo Chen 	}
46345334ee1SHaibo Chen 
46452e4c32bSHaibo Chen 	/*
46552e4c32bSHaibo Chen 	 * For USDHC, auto tuning circuit can not handle the async sdio
46652e4c32bSHaibo Chen 	 * device interrupt correctly. When sdio device use 4 data lines,
46752e4c32bSHaibo Chen 	 * async sdio interrupt will use the shared DAT[1], if enable auto
46852e4c32bSHaibo Chen 	 * tuning circuit check these 4 data lines, include the DAT[1],
46952e4c32bSHaibo Chen 	 * this circuit will detect this interrupt, take this as a data on
47052e4c32bSHaibo Chen 	 * DAT[1], and adjust the delay cell wrongly.
47152e4c32bSHaibo Chen 	 * This is the hardware design limitation, to avoid this, for sdio
47252e4c32bSHaibo Chen 	 * device, config the auto tuning circuit only check DAT[0] and CMD
47352e4c32bSHaibo Chen 	 * line.
47452e4c32bSHaibo Chen 	 */
47552e4c32bSHaibo Chen 	if (imx_data->init_card_type == MMC_TYPE_SDIO)
47652e4c32bSHaibo Chen 		auto_tune_buswidth = ESDHC_VEND_SPEC2_AUTO_TUNE_1BIT_EN;
47752e4c32bSHaibo Chen 
47845334ee1SHaibo Chen 	esdhc_clrset_le(host, ESDHC_VEND_SPEC2_AUTO_TUNE_MODE_MASK,
47945334ee1SHaibo Chen 			auto_tune_buswidth | ESDHC_VEND_SPEC2_AUTO_TUNE_CMD_EN,
48045334ee1SHaibo Chen 			ESDHC_VEND_SPEC2);
481c8c49a5aSHaibo Chen 
482c8c49a5aSHaibo Chen 	reg = readl(host->ioaddr + ESDHC_MIX_CTRL);
483c8c49a5aSHaibo Chen 	reg |= ESDHC_MIX_CTRL_AUTO_TUNE_EN;
484c8c49a5aSHaibo Chen 	writel(reg, host->ioaddr + ESDHC_MIX_CTRL);
48545334ee1SHaibo Chen }
48645334ee1SHaibo Chen 
esdhc_readl_le(struct sdhci_host * host,int reg)4877e29c306SWolfram Sang static u32 esdhc_readl_le(struct sdhci_host *host, int reg)
4887e29c306SWolfram Sang {
489361b8482SLucas Stach 	struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
490070e6d3fSJisheng Zhang 	struct pltfm_imx_data *imx_data = sdhci_pltfm_priv(pltfm_host);
491913413c3SShawn Guo 	u32 val = readl(host->ioaddr + reg);
492913413c3SShawn Guo 
4930322191eSDong Aisheng 	if (unlikely(reg == SDHCI_PRESENT_STATE)) {
4940322191eSDong Aisheng 		u32 fsl_prss = val;
4950322191eSDong Aisheng 		/* save the least 20 bits */
4960322191eSDong Aisheng 		val = fsl_prss & 0x000FFFFF;
4970322191eSDong Aisheng 		/* move dat[0-3] bits */
4980322191eSDong Aisheng 		val |= (fsl_prss & 0x0F000000) >> 4;
4990322191eSDong Aisheng 		/* move cmd line bit */
5000322191eSDong Aisheng 		val |= (fsl_prss & 0x00800000) << 1;
5010322191eSDong Aisheng 	}
5020322191eSDong Aisheng 
50397e4ba6aSRichard Zhu 	if (unlikely(reg == SDHCI_CAPABILITIES)) {
5046b4fb671SDong Aisheng 		/* ignore bit[0-15] as it stores cap_1 register val for mx6sl */
5056b4fb671SDong Aisheng 		if (imx_data->socdata->flags & ESDHC_FLAG_HAVE_CAP1)
5066b4fb671SDong Aisheng 			val &= 0xffff0000;
5076b4fb671SDong Aisheng 
50897e4ba6aSRichard Zhu 		/* In FSL esdhc IC module, only bit20 is used to indicate the
50997e4ba6aSRichard Zhu 		 * ADMA2 capability of esdhc, but this bit is messed up on
51097e4ba6aSRichard Zhu 		 * some SOCs (e.g. on MX25, MX35 this bit is set, but they
51197e4ba6aSRichard Zhu 		 * don't actually support ADMA2). So set the BROKEN_ADMA
512d04f8d5bSBenoît Thébaudeau 		 * quirk on MX25/35 platforms.
51397e4ba6aSRichard Zhu 		 */
51497e4ba6aSRichard Zhu 
51597e4ba6aSRichard Zhu 		if (val & SDHCI_CAN_DO_ADMA1) {
51697e4ba6aSRichard Zhu 			val &= ~SDHCI_CAN_DO_ADMA1;
51797e4ba6aSRichard Zhu 			val |= SDHCI_CAN_DO_ADMA2;
51897e4ba6aSRichard Zhu 		}
51997e4ba6aSRichard Zhu 	}
52097e4ba6aSRichard Zhu 
5216e9fd28eSDong Aisheng 	if (unlikely(reg == SDHCI_CAPABILITIES_1)) {
5226e9fd28eSDong Aisheng 		if (esdhc_is_usdhc(imx_data)) {
5236e9fd28eSDong Aisheng 			if (imx_data->socdata->flags & ESDHC_FLAG_HAVE_CAP1)
5246e9fd28eSDong Aisheng 				val = readl(host->ioaddr + SDHCI_CAPABILITIES) & 0xFFFF;
5256e9fd28eSDong Aisheng 			else
5266e9fd28eSDong Aisheng 				/* imx6q/dl does not have cap_1 register, fake one */
5270322191eSDong Aisheng 				val = SDHCI_SUPPORT_DDR50 | SDHCI_SUPPORT_SDR104
528888824bbSDong Aisheng 					| SDHCI_SUPPORT_SDR50
529da0295ffSDong Aisheng 					| SDHCI_USE_SDR50_TUNING
530a8e809ecSMasahiro Yamada 					| FIELD_PREP(SDHCI_RETUNING_MODE_MASK,
531a8e809ecSMasahiro Yamada 						     SDHCI_TUNING_MODE_3);
53228b07674SHaibo Chen 
53392748beaSStefan Agner 			/*
53492748beaSStefan Agner 			 * Do not advertise faster UHS modes if there are no
53592748beaSStefan Agner 			 * pinctrl states for 100MHz/200MHz.
53692748beaSStefan Agner 			 */
53725e8b9ebSShawn Guo 			if (IS_ERR_OR_NULL(imx_data->pins_100mhz))
53825e8b9ebSShawn Guo 				val &= ~(SDHCI_SUPPORT_SDR50 | SDHCI_SUPPORT_DDR50);
53925e8b9ebSShawn Guo 			if (IS_ERR_OR_NULL(imx_data->pins_200mhz))
54025e8b9ebSShawn Guo 				val &= ~(SDHCI_SUPPORT_SDR104 | SDHCI_SUPPORT_HS400);
5416e9fd28eSDong Aisheng 		}
5426e9fd28eSDong Aisheng 	}
5430322191eSDong Aisheng 
5449d61c009SShawn Guo 	if (unlikely(reg == SDHCI_MAX_CURRENT) && esdhc_is_usdhc(imx_data)) {
5450322191eSDong Aisheng 		val = 0;
546804a65b3SMasahiro Yamada 		val |= FIELD_PREP(SDHCI_MAX_CURRENT_330_MASK, 0xFF);
547804a65b3SMasahiro Yamada 		val |= FIELD_PREP(SDHCI_MAX_CURRENT_300_MASK, 0xFF);
548804a65b3SMasahiro Yamada 		val |= FIELD_PREP(SDHCI_MAX_CURRENT_180_MASK, 0xFF);
5490322191eSDong Aisheng 	}
5500322191eSDong Aisheng 
55197e4ba6aSRichard Zhu 	if (unlikely(reg == SDHCI_INT_STATUS)) {
55260bf6396SShawn Guo 		if (val & ESDHC_INT_VENDOR_SPEC_DMA_ERR) {
55360bf6396SShawn Guo 			val &= ~ESDHC_INT_VENDOR_SPEC_DMA_ERR;
55497e4ba6aSRichard Zhu 			val |= SDHCI_INT_ADMA_ERROR;
55597e4ba6aSRichard Zhu 		}
556361b8482SLucas Stach 
557361b8482SLucas Stach 		/*
558361b8482SLucas Stach 		 * mask off the interrupt we get in response to the manually
559361b8482SLucas Stach 		 * sent CMD12
560361b8482SLucas Stach 		 */
561361b8482SLucas Stach 		if ((imx_data->multiblock_status == WAIT_FOR_INT) &&
562361b8482SLucas Stach 		    ((val & SDHCI_INT_RESPONSE) == SDHCI_INT_RESPONSE)) {
563361b8482SLucas Stach 			val &= ~SDHCI_INT_RESPONSE;
564361b8482SLucas Stach 			writel(SDHCI_INT_RESPONSE, host->ioaddr +
565361b8482SLucas Stach 						   SDHCI_INT_STATUS);
566361b8482SLucas Stach 			imx_data->multiblock_status = NO_CMD_PENDING;
567361b8482SLucas Stach 		}
56897e4ba6aSRichard Zhu 	}
56997e4ba6aSRichard Zhu 
5707e29c306SWolfram Sang 	return val;
5717e29c306SWolfram Sang }
5727e29c306SWolfram Sang 
esdhc_writel_le(struct sdhci_host * host,u32 val,int reg)5737e29c306SWolfram Sang static void esdhc_writel_le(struct sdhci_host *host, u32 val, int reg)
5747e29c306SWolfram Sang {
575e149860dSRichard Zhu 	struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
576070e6d3fSJisheng Zhang 	struct pltfm_imx_data *imx_data = sdhci_pltfm_priv(pltfm_host);
5770d58864bSTony Lin 	u32 data;
578e149860dSRichard Zhu 
57977da3da0SAaron Brice 	if (unlikely(reg == SDHCI_INT_ENABLE || reg == SDHCI_SIGNAL_ENABLE ||
58077da3da0SAaron Brice 			reg == SDHCI_INT_STATUS)) {
581b7321042SDong Aisheng 		if ((val & SDHCI_INT_CARD_INT) && !esdhc_is_usdhc(imx_data)) {
5820d58864bSTony Lin 			/*
5830d58864bSTony Lin 			 * Clear and then set D3CD bit to avoid missing the
584d04f8d5bSBenoît Thébaudeau 			 * card interrupt. This is an eSDHC controller problem
5850d58864bSTony Lin 			 * so we need to apply the following workaround: clear
5860d58864bSTony Lin 			 * and set D3CD bit will make eSDHC re-sample the card
5870d58864bSTony Lin 			 * interrupt. In case a card interrupt was lost,
5880d58864bSTony Lin 			 * re-sample it by the following steps.
5890d58864bSTony Lin 			 */
5900d58864bSTony Lin 			data = readl(host->ioaddr + SDHCI_HOST_CONTROL);
59160bf6396SShawn Guo 			data &= ~ESDHC_CTRL_D3CD;
5920d58864bSTony Lin 			writel(data, host->ioaddr + SDHCI_HOST_CONTROL);
59360bf6396SShawn Guo 			data |= ESDHC_CTRL_D3CD;
5940d58864bSTony Lin 			writel(data, host->ioaddr + SDHCI_HOST_CONTROL);
5950d58864bSTony Lin 		}
596915be485SDong Aisheng 
597915be485SDong Aisheng 		if (val & SDHCI_INT_ADMA_ERROR) {
598915be485SDong Aisheng 			val &= ~SDHCI_INT_ADMA_ERROR;
599915be485SDong Aisheng 			val |= ESDHC_INT_VENDOR_SPEC_DMA_ERR;
600915be485SDong Aisheng 		}
6010d58864bSTony Lin 	}
6020d58864bSTony Lin 
603f47c4bbfSShawn Guo 	if (unlikely((imx_data->socdata->flags & ESDHC_FLAG_MULTIBLK_NO_INT)
60458ac8177SRichard Zhu 				&& (reg == SDHCI_INT_STATUS)
60558ac8177SRichard Zhu 				&& (val & SDHCI_INT_DATA_END))) {
60658ac8177SRichard Zhu 			u32 v;
60760bf6396SShawn Guo 			v = readl(host->ioaddr + ESDHC_VENDOR_SPEC);
60860bf6396SShawn Guo 			v &= ~ESDHC_VENDOR_SPEC_SDIO_QUIRK;
60960bf6396SShawn Guo 			writel(v, host->ioaddr + ESDHC_VENDOR_SPEC);
610361b8482SLucas Stach 
611361b8482SLucas Stach 			if (imx_data->multiblock_status == MULTIBLK_IN_PROCESS)
612361b8482SLucas Stach 			{
613361b8482SLucas Stach 				/* send a manual CMD12 with RESPTYP=none */
614361b8482SLucas Stach 				data = MMC_STOP_TRANSMISSION << 24 |
615361b8482SLucas Stach 				       SDHCI_CMD_ABORTCMD << 16;
616361b8482SLucas Stach 				writel(data, host->ioaddr + SDHCI_TRANSFER_MODE);
617361b8482SLucas Stach 				imx_data->multiblock_status = WAIT_FOR_INT;
618361b8482SLucas Stach 			}
61958ac8177SRichard Zhu 	}
62058ac8177SRichard Zhu 
6217e29c306SWolfram Sang 	writel(val, host->ioaddr + reg);
6227e29c306SWolfram Sang }
6237e29c306SWolfram Sang 
esdhc_readw_le(struct sdhci_host * host,int reg)62495f25efeSWolfram Sang static u16 esdhc_readw_le(struct sdhci_host *host, int reg)
62595f25efeSWolfram Sang {
626ef4d0888SShawn Guo 	struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
627070e6d3fSJisheng Zhang 	struct pltfm_imx_data *imx_data = sdhci_pltfm_priv(pltfm_host);
6280322191eSDong Aisheng 	u16 ret = 0;
6290322191eSDong Aisheng 	u32 val;
630ef4d0888SShawn Guo 
63195a2482aSShawn Guo 	if (unlikely(reg == SDHCI_HOST_VERSION)) {
632ef4d0888SShawn Guo 		reg ^= 2;
6339d61c009SShawn Guo 		if (esdhc_is_usdhc(imx_data)) {
63495a2482aSShawn Guo 			/*
635ef4d0888SShawn Guo 			 * The usdhc register returns a wrong host version.
636ef4d0888SShawn Guo 			 * Correct it here.
63795a2482aSShawn Guo 			 */
638ef4d0888SShawn Guo 			return SDHCI_SPEC_300;
639ef4d0888SShawn Guo 		}
64095a2482aSShawn Guo 	}
64195f25efeSWolfram Sang 
6420322191eSDong Aisheng 	if (unlikely(reg == SDHCI_HOST_CONTROL2)) {
6430322191eSDong Aisheng 		val = readl(host->ioaddr + ESDHC_VENDOR_SPEC);
6440322191eSDong Aisheng 		if (val & ESDHC_VENDOR_SPEC_VSELECT)
6450322191eSDong Aisheng 			ret |= SDHCI_CTRL_VDD_180;
6460322191eSDong Aisheng 
6479d61c009SShawn Guo 		if (esdhc_is_usdhc(imx_data)) {
6486e9fd28eSDong Aisheng 			if (imx_data->socdata->flags & ESDHC_FLAG_MAN_TUNING)
6490322191eSDong Aisheng 				val = readl(host->ioaddr + ESDHC_MIX_CTRL);
6506e9fd28eSDong Aisheng 			else if (imx_data->socdata->flags & ESDHC_FLAG_STD_TUNING)
6516e9fd28eSDong Aisheng 				/* the std tuning bits is in ACMD12_ERR for imx6sl */
652869f8a69SAdrian Hunter 				val = readl(host->ioaddr + SDHCI_AUTO_CMD_STATUS);
6536e9fd28eSDong Aisheng 		}
6546e9fd28eSDong Aisheng 
6550322191eSDong Aisheng 		if (val & ESDHC_MIX_CTRL_EXE_TUNE)
6560322191eSDong Aisheng 			ret |= SDHCI_CTRL_EXEC_TUNING;
6570322191eSDong Aisheng 		if (val & ESDHC_MIX_CTRL_SMPCLK_SEL)
6580322191eSDong Aisheng 			ret |= SDHCI_CTRL_TUNED_CLK;
6590322191eSDong Aisheng 
6600322191eSDong Aisheng 		ret &= ~SDHCI_CTRL_PRESET_VAL_ENABLE;
6610322191eSDong Aisheng 
6620322191eSDong Aisheng 		return ret;
6630322191eSDong Aisheng 	}
6640322191eSDong Aisheng 
6657dd109efSDong Aisheng 	if (unlikely(reg == SDHCI_TRANSFER_MODE)) {
6667dd109efSDong Aisheng 		if (esdhc_is_usdhc(imx_data)) {
6677dd109efSDong Aisheng 			u32 m = readl(host->ioaddr + ESDHC_MIX_CTRL);
6687dd109efSDong Aisheng 			ret = m & ESDHC_MIX_CTRL_SDHCI_MASK;
6697dd109efSDong Aisheng 			/* Swap AC23 bit */
6707dd109efSDong Aisheng 			if (m & ESDHC_MIX_CTRL_AC23EN) {
6717dd109efSDong Aisheng 				ret &= ~ESDHC_MIX_CTRL_AC23EN;
6727dd109efSDong Aisheng 				ret |= SDHCI_TRNS_AUTO_CMD23;
6737dd109efSDong Aisheng 			}
6747dd109efSDong Aisheng 		} else {
6757dd109efSDong Aisheng 			ret = readw(host->ioaddr + SDHCI_TRANSFER_MODE);
6767dd109efSDong Aisheng 		}
6777dd109efSDong Aisheng 
6787dd109efSDong Aisheng 		return ret;
6797dd109efSDong Aisheng 	}
6807dd109efSDong Aisheng 
68195f25efeSWolfram Sang 	return readw(host->ioaddr + reg);
68295f25efeSWolfram Sang }
68395f25efeSWolfram Sang 
esdhc_writew_le(struct sdhci_host * host,u16 val,int reg)68495f25efeSWolfram Sang static void esdhc_writew_le(struct sdhci_host *host, u16 val, int reg)
68595f25efeSWolfram Sang {
68695f25efeSWolfram Sang 	struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
687070e6d3fSJisheng Zhang 	struct pltfm_imx_data *imx_data = sdhci_pltfm_priv(pltfm_host);
6880322191eSDong Aisheng 	u32 new_val = 0;
68995f25efeSWolfram Sang 
69095f25efeSWolfram Sang 	switch (reg) {
6910322191eSDong Aisheng 	case SDHCI_CLOCK_CONTROL:
6920322191eSDong Aisheng 		new_val = readl(host->ioaddr + ESDHC_VENDOR_SPEC);
6930322191eSDong Aisheng 		if (val & SDHCI_CLOCK_CARD_EN)
6940322191eSDong Aisheng 			new_val |= ESDHC_VENDOR_SPEC_FRC_SDCLK_ON;
6950322191eSDong Aisheng 		else
6960322191eSDong Aisheng 			new_val &= ~ESDHC_VENDOR_SPEC_FRC_SDCLK_ON;
6970322191eSDong Aisheng 		writel(new_val, host->ioaddr + ESDHC_VENDOR_SPEC);
698f581e909SHaibo Chen 		if (!(new_val & ESDHC_VENDOR_SPEC_FRC_SDCLK_ON))
699f581e909SHaibo Chen 			esdhc_wait_for_card_clock_gate_off(host);
7000322191eSDong Aisheng 		return;
7010322191eSDong Aisheng 	case SDHCI_HOST_CONTROL2:
7020322191eSDong Aisheng 		new_val = readl(host->ioaddr + ESDHC_VENDOR_SPEC);
7030322191eSDong Aisheng 		if (val & SDHCI_CTRL_VDD_180)
7040322191eSDong Aisheng 			new_val |= ESDHC_VENDOR_SPEC_VSELECT;
7050322191eSDong Aisheng 		else
7060322191eSDong Aisheng 			new_val &= ~ESDHC_VENDOR_SPEC_VSELECT;
7070322191eSDong Aisheng 		writel(new_val, host->ioaddr + ESDHC_VENDOR_SPEC);
708a0dbbdc2SHaibo Chen 		if (imx_data->socdata->flags & ESDHC_FLAG_STD_TUNING) {
709869f8a69SAdrian Hunter 			u32 v = readl(host->ioaddr + SDHCI_AUTO_CMD_STATUS);
7106e9fd28eSDong Aisheng 			u32 m = readl(host->ioaddr + ESDHC_MIX_CTRL);
7118b2bb0adSDong Aisheng 			if (val & SDHCI_CTRL_TUNED_CLK) {
7128b2bb0adSDong Aisheng 				v |= ESDHC_MIX_CTRL_SMPCLK_SEL;
7136e9fd28eSDong Aisheng 			} else {
7148b2bb0adSDong Aisheng 				v &= ~ESDHC_MIX_CTRL_SMPCLK_SEL;
7156e9fd28eSDong Aisheng 				m &= ~ESDHC_MIX_CTRL_FBCLK_SEL;
7166e9fd28eSDong Aisheng 			}
7176e9fd28eSDong Aisheng 
7188b2bb0adSDong Aisheng 			if (val & SDHCI_CTRL_EXEC_TUNING) {
7198b2bb0adSDong Aisheng 				v |= ESDHC_MIX_CTRL_EXE_TUNE;
7208b2bb0adSDong Aisheng 				m |= ESDHC_MIX_CTRL_FBCLK_SEL;
7218b2bb0adSDong Aisheng 			} else {
7228b2bb0adSDong Aisheng 				v &= ~ESDHC_MIX_CTRL_EXE_TUNE;
7238b2bb0adSDong Aisheng 			}
7246e9fd28eSDong Aisheng 
725869f8a69SAdrian Hunter 			writel(v, host->ioaddr + SDHCI_AUTO_CMD_STATUS);
7266e9fd28eSDong Aisheng 			writel(m, host->ioaddr + ESDHC_MIX_CTRL);
7276e9fd28eSDong Aisheng 		}
7280322191eSDong Aisheng 		return;
72995f25efeSWolfram Sang 	case SDHCI_TRANSFER_MODE:
730f47c4bbfSShawn Guo 		if ((imx_data->socdata->flags & ESDHC_FLAG_MULTIBLK_NO_INT)
73158ac8177SRichard Zhu 				&& (host->cmd->opcode == SD_IO_RW_EXTENDED)
73258ac8177SRichard Zhu 				&& (host->cmd->data->blocks > 1)
73358ac8177SRichard Zhu 				&& (host->cmd->data->flags & MMC_DATA_READ)) {
73458ac8177SRichard Zhu 			u32 v;
73560bf6396SShawn Guo 			v = readl(host->ioaddr + ESDHC_VENDOR_SPEC);
73660bf6396SShawn Guo 			v |= ESDHC_VENDOR_SPEC_SDIO_QUIRK;
73760bf6396SShawn Guo 			writel(v, host->ioaddr + ESDHC_VENDOR_SPEC);
73858ac8177SRichard Zhu 		}
73969f54698SShawn Guo 
7409d61c009SShawn Guo 		if (esdhc_is_usdhc(imx_data)) {
7413fbd4322SAndrew Gabbasov 			u32 wml;
74269f54698SShawn Guo 			u32 m = readl(host->ioaddr + ESDHC_MIX_CTRL);
7432a15f981SShawn Guo 			/* Swap AC23 bit */
7442a15f981SShawn Guo 			if (val & SDHCI_TRNS_AUTO_CMD23) {
7452a15f981SShawn Guo 				val &= ~SDHCI_TRNS_AUTO_CMD23;
7462a15f981SShawn Guo 				val |= ESDHC_MIX_CTRL_AC23EN;
7472a15f981SShawn Guo 			}
7482a15f981SShawn Guo 			m = val | (m & ~ESDHC_MIX_CTRL_SDHCI_MASK);
74969f54698SShawn Guo 			writel(m, host->ioaddr + ESDHC_MIX_CTRL);
7503fbd4322SAndrew Gabbasov 
7513fbd4322SAndrew Gabbasov 			/* Set watermark levels for PIO access to maximum value
7523fbd4322SAndrew Gabbasov 			 * (128 words) to accommodate full 512 bytes buffer.
7533fbd4322SAndrew Gabbasov 			 * For DMA access restore the levels to default value.
7543fbd4322SAndrew Gabbasov 			 */
7553fbd4322SAndrew Gabbasov 			m = readl(host->ioaddr + ESDHC_WTMK_LVL);
756e534b82fSHaibo Chen 			if (val & SDHCI_TRNS_DMA) {
7573fbd4322SAndrew Gabbasov 				wml = ESDHC_WTMK_LVL_WML_VAL_DEF;
758e534b82fSHaibo Chen 			} else {
759e534b82fSHaibo Chen 				u8 ctrl;
7603fbd4322SAndrew Gabbasov 				wml = ESDHC_WTMK_LVL_WML_VAL_MAX;
761e534b82fSHaibo Chen 
762e534b82fSHaibo Chen 				/*
763e534b82fSHaibo Chen 				 * Since already disable DMA mode, so also need
764e534b82fSHaibo Chen 				 * to clear the DMASEL. Otherwise, for standard
765e534b82fSHaibo Chen 				 * tuning, when send tuning command, usdhc will
766e534b82fSHaibo Chen 				 * still prefetch the ADMA script from wrong
767e534b82fSHaibo Chen 				 * DMA address, then we will see IOMMU report
768e534b82fSHaibo Chen 				 * some error which show lack of TLB mapping.
769e534b82fSHaibo Chen 				 */
770e534b82fSHaibo Chen 				ctrl = sdhci_readb(host, SDHCI_HOST_CONTROL);
771e534b82fSHaibo Chen 				ctrl &= ~SDHCI_CTRL_DMA_MASK;
772e534b82fSHaibo Chen 				sdhci_writeb(host, ctrl, SDHCI_HOST_CONTROL);
773e534b82fSHaibo Chen 			}
7743fbd4322SAndrew Gabbasov 			m &= ~(ESDHC_WTMK_LVL_RD_WML_MASK |
7753fbd4322SAndrew Gabbasov 			       ESDHC_WTMK_LVL_WR_WML_MASK);
7763fbd4322SAndrew Gabbasov 			m |= (wml << ESDHC_WTMK_LVL_RD_WML_SHIFT) |
7773fbd4322SAndrew Gabbasov 			     (wml << ESDHC_WTMK_LVL_WR_WML_SHIFT);
7783fbd4322SAndrew Gabbasov 			writel(m, host->ioaddr + ESDHC_WTMK_LVL);
77969f54698SShawn Guo 		} else {
78069f54698SShawn Guo 			/*
78169f54698SShawn Guo 			 * Postpone this write, we must do it together with a
78269f54698SShawn Guo 			 * command write that is down below.
78369f54698SShawn Guo 			 */
784e149860dSRichard Zhu 			imx_data->scratchpad = val;
78569f54698SShawn Guo 		}
78695f25efeSWolfram Sang 		return;
78795f25efeSWolfram Sang 	case SDHCI_COMMAND:
788361b8482SLucas Stach 		if (host->cmd->opcode == MMC_STOP_TRANSMISSION)
78958ac8177SRichard Zhu 			val |= SDHCI_CMD_ABORTCMD;
79095a2482aSShawn Guo 
791361b8482SLucas Stach 		if ((host->cmd->opcode == MMC_SET_BLOCK_COUNT) &&
792f47c4bbfSShawn Guo 		    (imx_data->socdata->flags & ESDHC_FLAG_MULTIBLK_NO_INT))
793361b8482SLucas Stach 			imx_data->multiblock_status = MULTIBLK_IN_PROCESS;
794361b8482SLucas Stach 
7959d61c009SShawn Guo 		if (esdhc_is_usdhc(imx_data))
79695a2482aSShawn Guo 			writel(val << 16,
79795a2482aSShawn Guo 			       host->ioaddr + SDHCI_TRANSFER_MODE);
79869f54698SShawn Guo 		else
799e149860dSRichard Zhu 			writel(val << 16 | imx_data->scratchpad,
80095f25efeSWolfram Sang 			       host->ioaddr + SDHCI_TRANSFER_MODE);
80195f25efeSWolfram Sang 		return;
80295f25efeSWolfram Sang 	case SDHCI_BLOCK_SIZE:
80395f25efeSWolfram Sang 		val &= ~SDHCI_MAKE_BLKSZ(0x7, 0);
80495f25efeSWolfram Sang 		break;
80595f25efeSWolfram Sang 	}
80695f25efeSWolfram Sang 	esdhc_clrset_le(host, 0xffff, val, reg);
80795f25efeSWolfram Sang }
80895f25efeSWolfram Sang 
esdhc_readb_le(struct sdhci_host * host,int reg)80977da3da0SAaron Brice static u8 esdhc_readb_le(struct sdhci_host *host, int reg)
81077da3da0SAaron Brice {
81177da3da0SAaron Brice 	u8 ret;
81277da3da0SAaron Brice 	u32 val;
81377da3da0SAaron Brice 
81477da3da0SAaron Brice 	switch (reg) {
81577da3da0SAaron Brice 	case SDHCI_HOST_CONTROL:
81677da3da0SAaron Brice 		val = readl(host->ioaddr + reg);
81777da3da0SAaron Brice 
81877da3da0SAaron Brice 		ret = val & SDHCI_CTRL_LED;
81977da3da0SAaron Brice 		ret |= (val >> 5) & SDHCI_CTRL_DMA_MASK;
82077da3da0SAaron Brice 		ret |= (val & ESDHC_CTRL_4BITBUS);
82177da3da0SAaron Brice 		ret |= (val & ESDHC_CTRL_8BITBUS) << 3;
82277da3da0SAaron Brice 		return ret;
82377da3da0SAaron Brice 	}
82477da3da0SAaron Brice 
82577da3da0SAaron Brice 	return readb(host->ioaddr + reg);
82677da3da0SAaron Brice }
82777da3da0SAaron Brice 
esdhc_writeb_le(struct sdhci_host * host,u8 val,int reg)82895f25efeSWolfram Sang static void esdhc_writeb_le(struct sdhci_host *host, u8 val, int reg)
82995f25efeSWolfram Sang {
8309a0985b7SWilson Callan 	struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
831070e6d3fSJisheng Zhang 	struct pltfm_imx_data *imx_data = sdhci_pltfm_priv(pltfm_host);
83281a0a8bcSBenoît Thébaudeau 	u32 new_val = 0;
833af51079eSSascha Hauer 	u32 mask;
83495f25efeSWolfram Sang 
83595f25efeSWolfram Sang 	switch (reg) {
83695f25efeSWolfram Sang 	case SDHCI_POWER_CONTROL:
83795f25efeSWolfram Sang 		/*
83895f25efeSWolfram Sang 		 * FSL put some DMA bits here
83995f25efeSWolfram Sang 		 * If your board has a regulator, code should be here
84095f25efeSWolfram Sang 		 */
84195f25efeSWolfram Sang 		return;
84295f25efeSWolfram Sang 	case SDHCI_HOST_CONTROL:
8436b40d182SShawn Guo 		/* FSL messed up here, so we need to manually compose it. */
844af51079eSSascha Hauer 		new_val = val & SDHCI_CTRL_LED;
8457122bbb0SMasanari Iida 		/* ensure the endianness */
84695f25efeSWolfram Sang 		new_val |= ESDHC_HOST_CONTROL_LE;
8479a0985b7SWilson Callan 		/* bits 8&9 are reserved on mx25 */
8489a0985b7SWilson Callan 		if (!is_imx25_esdhc(imx_data)) {
84995f25efeSWolfram Sang 			/* DMA mode bits are shifted */
85095f25efeSWolfram Sang 			new_val |= (val & SDHCI_CTRL_DMA_MASK) << 5;
8519a0985b7SWilson Callan 		}
85295f25efeSWolfram Sang 
853af51079eSSascha Hauer 		/*
854af51079eSSascha Hauer 		 * Do not touch buswidth bits here. This is done in
855af51079eSSascha Hauer 		 * esdhc_pltfm_bus_width.
856f6825748SMartin Fuzzey 		 * Do not touch the D3CD bit either which is used for the
857d04f8d5bSBenoît Thébaudeau 		 * SDIO interrupt erratum workaround.
858af51079eSSascha Hauer 		 */
859f6825748SMartin Fuzzey 		mask = 0xffff & ~(ESDHC_CTRL_BUSWIDTH_MASK | ESDHC_CTRL_D3CD);
860af51079eSSascha Hauer 
861af51079eSSascha Hauer 		esdhc_clrset_le(host, mask, new_val, reg);
86295f25efeSWolfram Sang 		return;
86381a0a8bcSBenoît Thébaudeau 	case SDHCI_SOFTWARE_RESET:
86481a0a8bcSBenoît Thébaudeau 		if (val & SDHCI_RESET_DATA)
86581a0a8bcSBenoît Thébaudeau 			new_val = readl(host->ioaddr + SDHCI_HOST_CONTROL);
86681a0a8bcSBenoît Thébaudeau 		break;
86795f25efeSWolfram Sang 	}
86895f25efeSWolfram Sang 	esdhc_clrset_le(host, 0xff, val, reg);
869913413c3SShawn Guo 
87081a0a8bcSBenoît Thébaudeau 	if (reg == SDHCI_SOFTWARE_RESET) {
87181a0a8bcSBenoît Thébaudeau 		if (val & SDHCI_RESET_ALL) {
872913413c3SShawn Guo 			/*
87381a0a8bcSBenoît Thébaudeau 			 * The esdhc has a design violation to SDHC spec which
87481a0a8bcSBenoît Thébaudeau 			 * tells that software reset should not affect card
87581a0a8bcSBenoît Thébaudeau 			 * detection circuit. But esdhc clears its SYSCTL
87681a0a8bcSBenoît Thébaudeau 			 * register bits [0..2] during the software reset. This
87781a0a8bcSBenoît Thébaudeau 			 * will stop those clocks that card detection circuit
87881a0a8bcSBenoît Thébaudeau 			 * relies on. To work around it, we turn the clocks on
87981a0a8bcSBenoît Thébaudeau 			 * back to keep card detection circuit functional.
880913413c3SShawn Guo 			 */
881913413c3SShawn Guo 			esdhc_clrset_le(host, 0x7, 0x7, ESDHC_SYSTEM_CONTROL);
88258c8c4fbSShawn Guo 			/*
88358c8c4fbSShawn Guo 			 * The reset on usdhc fails to clear MIX_CTRL register.
88458c8c4fbSShawn Guo 			 * Do it manually here.
88558c8c4fbSShawn Guo 			 */
886de5bdbffSDong Aisheng 			if (esdhc_is_usdhc(imx_data)) {
88781a0a8bcSBenoît Thébaudeau 				/*
88881a0a8bcSBenoît Thébaudeau 				 * the tuning bits should be kept during reset
88981a0a8bcSBenoît Thébaudeau 				 */
890d131a71cSDong Aisheng 				new_val = readl(host->ioaddr + ESDHC_MIX_CTRL);
891d131a71cSDong Aisheng 				writel(new_val & ESDHC_MIX_CTRL_TUNING_MASK,
892d131a71cSDong Aisheng 						host->ioaddr + ESDHC_MIX_CTRL);
893de5bdbffSDong Aisheng 				imx_data->is_ddr = 0;
894de5bdbffSDong Aisheng 			}
89581a0a8bcSBenoît Thébaudeau 		} else if (val & SDHCI_RESET_DATA) {
89681a0a8bcSBenoît Thébaudeau 			/*
89781a0a8bcSBenoît Thébaudeau 			 * The eSDHC DAT line software reset clears at least the
89881a0a8bcSBenoît Thébaudeau 			 * data transfer width on i.MX25, so make sure that the
89981a0a8bcSBenoît Thébaudeau 			 * Host Control register is unaffected.
90081a0a8bcSBenoît Thébaudeau 			 */
90181a0a8bcSBenoît Thébaudeau 			esdhc_clrset_le(host, 0xff, new_val,
90281a0a8bcSBenoît Thébaudeau 					SDHCI_HOST_CONTROL);
90381a0a8bcSBenoît Thébaudeau 		}
90458c8c4fbSShawn Guo 	}
90595f25efeSWolfram Sang }
90695f25efeSWolfram Sang 
esdhc_pltfm_get_max_clock(struct sdhci_host * host)9070ddf03c9SLucas Stach static unsigned int esdhc_pltfm_get_max_clock(struct sdhci_host *host)
9080ddf03c9SLucas Stach {
9090ddf03c9SLucas Stach 	struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
9100ddf03c9SLucas Stach 
911a974862fSDong Aisheng 	return pltfm_host->clock;
9120ddf03c9SLucas Stach }
9130ddf03c9SLucas Stach 
esdhc_pltfm_get_min_clock(struct sdhci_host * host)91495f25efeSWolfram Sang static unsigned int esdhc_pltfm_get_min_clock(struct sdhci_host *host)
91595f25efeSWolfram Sang {
91695f25efeSWolfram Sang 	struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
91795f25efeSWolfram Sang 
918a974862fSDong Aisheng 	return pltfm_host->clock / 256 / 16;
91995f25efeSWolfram Sang }
92095f25efeSWolfram Sang 
esdhc_pltfm_set_clock(struct sdhci_host * host,unsigned int clock)9218ba9580aSLucas Stach static inline void esdhc_pltfm_set_clock(struct sdhci_host *host,
9228ba9580aSLucas Stach 					 unsigned int clock)
9238ba9580aSLucas Stach {
9248ba9580aSLucas Stach 	struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
925070e6d3fSJisheng Zhang 	struct pltfm_imx_data *imx_data = sdhci_pltfm_priv(pltfm_host);
926a974862fSDong Aisheng 	unsigned int host_clock = pltfm_host->clock;
9275143c953SBenoît Thébaudeau 	int ddr_pre_div = imx_data->is_ddr ? 2 : 1;
9285143c953SBenoît Thébaudeau 	int pre_div = 1;
929d31fc00aSDong Aisheng 	int div = 1;
930f581e909SHaibo Chen 	int ret;
931fed2f6e2SDong Aisheng 	u32 temp, val;
9328ba9580aSLucas Stach 
9339d61c009SShawn Guo 	if (esdhc_is_usdhc(imx_data)) {
934fed2f6e2SDong Aisheng 		val = readl(host->ioaddr + ESDHC_VENDOR_SPEC);
935fed2f6e2SDong Aisheng 		writel(val & ~ESDHC_VENDOR_SPEC_FRC_SDCLK_ON,
936fed2f6e2SDong Aisheng 			host->ioaddr + ESDHC_VENDOR_SPEC);
937f581e909SHaibo Chen 		esdhc_wait_for_card_clock_gate_off(host);
938fed2f6e2SDong Aisheng 	}
93973e736f8SStefan Agner 
94073e736f8SStefan Agner 	if (clock == 0) {
94173e736f8SStefan Agner 		host->mmc->actual_clock = 0;
942373073efSRussell King 		return;
943fed2f6e2SDong Aisheng 	}
944d31fc00aSDong Aisheng 
945499ed50fSBenoît Thébaudeau 	/* For i.MX53 eSDHCv3, SYSCTL.SDCLKFS may not be set to 0. */
946499ed50fSBenoît Thébaudeau 	if (is_imx53_esdhc(imx_data)) {
947499ed50fSBenoît Thébaudeau 		/*
948499ed50fSBenoît Thébaudeau 		 * According to the i.MX53 reference manual, if DLLCTRL[10] can
949499ed50fSBenoît Thébaudeau 		 * be set, then the controller is eSDHCv3, else it is eSDHCv2.
950499ed50fSBenoît Thébaudeau 		 */
951499ed50fSBenoît Thébaudeau 		val = readl(host->ioaddr + ESDHC_DLL_CTRL);
952499ed50fSBenoît Thébaudeau 		writel(val | BIT(10), host->ioaddr + ESDHC_DLL_CTRL);
953499ed50fSBenoît Thébaudeau 		temp = readl(host->ioaddr + ESDHC_DLL_CTRL);
954499ed50fSBenoît Thébaudeau 		writel(val, host->ioaddr + ESDHC_DLL_CTRL);
955499ed50fSBenoît Thébaudeau 		if (temp & BIT(10))
956499ed50fSBenoît Thébaudeau 			pre_div = 2;
957499ed50fSBenoît Thébaudeau 	}
958499ed50fSBenoît Thébaudeau 
959d31fc00aSDong Aisheng 	temp = sdhci_readl(host, ESDHC_SYSTEM_CONTROL);
960d31fc00aSDong Aisheng 	temp &= ~(ESDHC_CLOCK_IPGEN | ESDHC_CLOCK_HCKEN | ESDHC_CLOCK_PEREN
961d31fc00aSDong Aisheng 		| ESDHC_CLOCK_MASK);
962d31fc00aSDong Aisheng 	sdhci_writel(host, temp, ESDHC_SYSTEM_CONTROL);
963d31fc00aSDong Aisheng 
964*5ae4b0d8SGiulio Benetti 	if ((imx_data->socdata->flags & ESDHC_FLAG_ERR010450) &&
965*5ae4b0d8SGiulio Benetti 	    (!(host->quirks2 & SDHCI_QUIRK2_NO_1_8_V))) {
966af6a50d4SBOUGH CHEN 		unsigned int max_clock;
967af6a50d4SBOUGH CHEN 
968af6a50d4SBOUGH CHEN 		max_clock = imx_data->is_ddr ? 45000000 : 150000000;
969af6a50d4SBOUGH CHEN 
970af6a50d4SBOUGH CHEN 		clock = min(clock, max_clock);
971af6a50d4SBOUGH CHEN 	}
972af6a50d4SBOUGH CHEN 
9735143c953SBenoît Thébaudeau 	while (host_clock / (16 * pre_div * ddr_pre_div) > clock &&
9745143c953SBenoît Thébaudeau 			pre_div < 256)
975d31fc00aSDong Aisheng 		pre_div *= 2;
976d31fc00aSDong Aisheng 
9775143c953SBenoît Thébaudeau 	while (host_clock / (div * pre_div * ddr_pre_div) > clock && div < 16)
978d31fc00aSDong Aisheng 		div++;
979d31fc00aSDong Aisheng 
9805143c953SBenoît Thébaudeau 	host->mmc->actual_clock = host_clock / (div * pre_div * ddr_pre_div);
981d31fc00aSDong Aisheng 	dev_dbg(mmc_dev(host->mmc), "desired SD clock: %d, actual: %d\n",
982e76b8559SDong Aisheng 		clock, host->mmc->actual_clock);
983d31fc00aSDong Aisheng 
984d31fc00aSDong Aisheng 	pre_div >>= 1;
985d31fc00aSDong Aisheng 	div--;
986d31fc00aSDong Aisheng 
987d31fc00aSDong Aisheng 	temp = sdhci_readl(host, ESDHC_SYSTEM_CONTROL);
988d31fc00aSDong Aisheng 	temp |= (ESDHC_CLOCK_IPGEN | ESDHC_CLOCK_HCKEN | ESDHC_CLOCK_PEREN
989d31fc00aSDong Aisheng 		| (div << ESDHC_DIVIDER_SHIFT)
990d31fc00aSDong Aisheng 		| (pre_div << ESDHC_PREDIV_SHIFT));
991d31fc00aSDong Aisheng 	sdhci_writel(host, temp, ESDHC_SYSTEM_CONTROL);
992fed2f6e2SDong Aisheng 
993f581e909SHaibo Chen 	/* need to wait the bit 3 of the PRSSTAT to be set, make sure card clock is stable */
994f581e909SHaibo Chen 	ret = readl_poll_timeout(host->ioaddr + ESDHC_PRSSTAT, temp,
995f581e909SHaibo Chen 				(temp & ESDHC_CLOCK_STABLE), 2, 100);
996f581e909SHaibo Chen 	if (ret == -ETIMEDOUT)
997f581e909SHaibo Chen 		dev_warn(mmc_dev(host->mmc), "card clock still not stable in 100us!.\n");
998f581e909SHaibo Chen 
9999d61c009SShawn Guo 	if (esdhc_is_usdhc(imx_data)) {
1000fed2f6e2SDong Aisheng 		val = readl(host->ioaddr + ESDHC_VENDOR_SPEC);
1001fed2f6e2SDong Aisheng 		writel(val | ESDHC_VENDOR_SPEC_FRC_SDCLK_ON,
1002fed2f6e2SDong Aisheng 			host->ioaddr + ESDHC_VENDOR_SPEC);
1003fed2f6e2SDong Aisheng 	}
1004fed2f6e2SDong Aisheng 
10058ba9580aSLucas Stach }
10068ba9580aSLucas Stach 
esdhc_pltfm_get_ro(struct sdhci_host * host)1007913413c3SShawn Guo static unsigned int esdhc_pltfm_get_ro(struct sdhci_host *host)
1008913413c3SShawn Guo {
1009842afc02SShawn Guo 	struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
1010070e6d3fSJisheng Zhang 	struct pltfm_imx_data *imx_data = sdhci_pltfm_priv(pltfm_host);
1011842afc02SShawn Guo 	struct esdhc_platform_data *boarddata = &imx_data->boarddata;
1012913413c3SShawn Guo 
1013913413c3SShawn Guo 	switch (boarddata->wp_type) {
1014913413c3SShawn Guo 	case ESDHC_WP_GPIO:
1015fbe5fdd1SShawn Guo 		return mmc_gpio_get_ro(host->mmc);
1016913413c3SShawn Guo 	case ESDHC_WP_CONTROLLER:
1017913413c3SShawn Guo 		return !(readl(host->ioaddr + SDHCI_PRESENT_STATE) &
1018913413c3SShawn Guo 			       SDHCI_WRITE_PROTECT);
1019913413c3SShawn Guo 	case ESDHC_WP_NONE:
1020913413c3SShawn Guo 		break;
1021913413c3SShawn Guo 	}
1022913413c3SShawn Guo 
1023913413c3SShawn Guo 	return -ENOSYS;
1024913413c3SShawn Guo }
1025913413c3SShawn Guo 
esdhc_pltfm_set_bus_width(struct sdhci_host * host,int width)10262317f56cSRussell King static void esdhc_pltfm_set_bus_width(struct sdhci_host *host, int width)
1027af51079eSSascha Hauer {
1028af51079eSSascha Hauer 	u32 ctrl;
1029af51079eSSascha Hauer 
1030af51079eSSascha Hauer 	switch (width) {
1031af51079eSSascha Hauer 	case MMC_BUS_WIDTH_8:
1032af51079eSSascha Hauer 		ctrl = ESDHC_CTRL_8BITBUS;
1033af51079eSSascha Hauer 		break;
1034af51079eSSascha Hauer 	case MMC_BUS_WIDTH_4:
1035af51079eSSascha Hauer 		ctrl = ESDHC_CTRL_4BITBUS;
1036af51079eSSascha Hauer 		break;
1037af51079eSSascha Hauer 	default:
1038af51079eSSascha Hauer 		ctrl = 0;
1039af51079eSSascha Hauer 		break;
1040af51079eSSascha Hauer 	}
1041af51079eSSascha Hauer 
1042af51079eSSascha Hauer 	esdhc_clrset_le(host, ESDHC_CTRL_BUSWIDTH_MASK, ctrl,
1043af51079eSSascha Hauer 			SDHCI_HOST_CONTROL);
1044af51079eSSascha Hauer }
1045af51079eSSascha Hauer 
esdhc_reset_tuning(struct sdhci_host * host)10464fb27869SHaibo Chen static void esdhc_reset_tuning(struct sdhci_host *host)
10474fb27869SHaibo Chen {
10484fb27869SHaibo Chen 	struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
10494fb27869SHaibo Chen 	struct pltfm_imx_data *imx_data = sdhci_pltfm_priv(pltfm_host);
10504fb27869SHaibo Chen 	u32 ctrl;
10514fb27869SHaibo Chen 	int ret;
10524fb27869SHaibo Chen 
10534fb27869SHaibo Chen 	/* Reset the tuning circuit */
10544fb27869SHaibo Chen 	if (esdhc_is_usdhc(imx_data)) {
10554fb27869SHaibo Chen 		ctrl = readl(host->ioaddr + ESDHC_MIX_CTRL);
1056c8c49a5aSHaibo Chen 		ctrl &= ~ESDHC_MIX_CTRL_AUTO_TUNE_EN;
1057c8c49a5aSHaibo Chen 		if (imx_data->socdata->flags & ESDHC_FLAG_MAN_TUNING) {
10584fb27869SHaibo Chen 			ctrl &= ~ESDHC_MIX_CTRL_SMPCLK_SEL;
10594fb27869SHaibo Chen 			ctrl &= ~ESDHC_MIX_CTRL_FBCLK_SEL;
10604fb27869SHaibo Chen 			writel(ctrl, host->ioaddr + ESDHC_MIX_CTRL);
10614fb27869SHaibo Chen 			writel(0, host->ioaddr + ESDHC_TUNE_CTRL_STATUS);
10624fb27869SHaibo Chen 		} else if (imx_data->socdata->flags & ESDHC_FLAG_STD_TUNING) {
1063c8c49a5aSHaibo Chen 			writel(ctrl, host->ioaddr + ESDHC_MIX_CTRL);
10644fb27869SHaibo Chen 			ctrl = readl(host->ioaddr + SDHCI_AUTO_CMD_STATUS);
10654fb27869SHaibo Chen 			ctrl &= ~ESDHC_MIX_CTRL_SMPCLK_SEL;
10664fb27869SHaibo Chen 			ctrl &= ~ESDHC_MIX_CTRL_EXE_TUNE;
10674fb27869SHaibo Chen 			writel(ctrl, host->ioaddr + SDHCI_AUTO_CMD_STATUS);
10684fb27869SHaibo Chen 			/* Make sure ESDHC_MIX_CTRL_EXE_TUNE cleared */
10694fb27869SHaibo Chen 			ret = readl_poll_timeout(host->ioaddr + SDHCI_AUTO_CMD_STATUS,
10704fb27869SHaibo Chen 				ctrl, !(ctrl & ESDHC_MIX_CTRL_EXE_TUNE), 1, 50);
10714fb27869SHaibo Chen 			if (ret == -ETIMEDOUT)
10724fb27869SHaibo Chen 				dev_warn(mmc_dev(host->mmc),
10734fb27869SHaibo Chen 				 "Warning! clear execute tuning bit failed\n");
10744fb27869SHaibo Chen 			/*
10754fb27869SHaibo Chen 			 * SDHCI_INT_DATA_AVAIL is W1C bit, set this bit will clear the
10764fb27869SHaibo Chen 			 * usdhc IP internal logic flag execute_tuning_with_clr_buf, which
10774fb27869SHaibo Chen 			 * will finally make sure the normal data transfer logic correct.
10784fb27869SHaibo Chen 			 */
10794fb27869SHaibo Chen 			ctrl = readl(host->ioaddr + SDHCI_INT_STATUS);
10804fb27869SHaibo Chen 			ctrl |= SDHCI_INT_DATA_AVAIL;
10814fb27869SHaibo Chen 			writel(ctrl, host->ioaddr + SDHCI_INT_STATUS);
10824fb27869SHaibo Chen 		}
10834fb27869SHaibo Chen 	}
10844fb27869SHaibo Chen }
10854fb27869SHaibo Chen 
usdhc_init_card(struct mmc_host * mmc,struct mmc_card * card)108652e4c32bSHaibo Chen static void usdhc_init_card(struct mmc_host *mmc, struct mmc_card *card)
108752e4c32bSHaibo Chen {
108852e4c32bSHaibo Chen 	struct sdhci_host *host = mmc_priv(mmc);
108952e4c32bSHaibo Chen 	struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
109052e4c32bSHaibo Chen 	struct pltfm_imx_data *imx_data = sdhci_pltfm_priv(pltfm_host);
109152e4c32bSHaibo Chen 
109252e4c32bSHaibo Chen 	imx_data->init_card_type = card->type;
109352e4c32bSHaibo Chen }
109452e4c32bSHaibo Chen 
usdhc_execute_tuning(struct mmc_host * mmc,u32 opcode)1095de3e1dd0SBOUGH CHEN static int usdhc_execute_tuning(struct mmc_host *mmc, u32 opcode)
1096de3e1dd0SBOUGH CHEN {
1097de3e1dd0SBOUGH CHEN 	struct sdhci_host *host = mmc_priv(mmc);
1098c8c49a5aSHaibo Chen 	int err;
1099de3e1dd0SBOUGH CHEN 
1100de3e1dd0SBOUGH CHEN 	/*
1101de3e1dd0SBOUGH CHEN 	 * i.MX uSDHC internally already uses a fixed optimized timing for
1102de3e1dd0SBOUGH CHEN 	 * DDR50, normally does not require tuning for DDR50 mode.
1103de3e1dd0SBOUGH CHEN 	 */
1104de3e1dd0SBOUGH CHEN 	if (host->timing == MMC_TIMING_UHS_DDR50)
1105de3e1dd0SBOUGH CHEN 		return 0;
1106de3e1dd0SBOUGH CHEN 
11074fb27869SHaibo Chen 	/*
11084fb27869SHaibo Chen 	 * Reset tuning circuit logic. If not, the previous tuning result
11094fb27869SHaibo Chen 	 * will impact current tuning, make current tuning can't set the
11104fb27869SHaibo Chen 	 * correct delay cell.
11114fb27869SHaibo Chen 	 */
11124fb27869SHaibo Chen 	esdhc_reset_tuning(host);
1113c8c49a5aSHaibo Chen 	err = sdhci_execute_tuning(mmc, opcode);
1114c8c49a5aSHaibo Chen 	/* If tuning done, enable auto tuning */
1115c8c49a5aSHaibo Chen 	if (!err && !host->tuning_err)
1116c8c49a5aSHaibo Chen 		usdhc_auto_tuning_mode_sel_and_en(host);
1117c8c49a5aSHaibo Chen 
1118c8c49a5aSHaibo Chen 	return err;
1119de3e1dd0SBOUGH CHEN }
1120de3e1dd0SBOUGH CHEN 
esdhc_prepare_tuning(struct sdhci_host * host,u32 val)11210322191eSDong Aisheng static void esdhc_prepare_tuning(struct sdhci_host *host, u32 val)
11220322191eSDong Aisheng {
11230322191eSDong Aisheng 	u32 reg;
11240ac4f496SHaibo Chen 	u8 sw_rst;
11250ac4f496SHaibo Chen 	int ret;
11260322191eSDong Aisheng 
11270322191eSDong Aisheng 	/* FIXME: delay a bit for card to be ready for next tuning due to errors */
11280322191eSDong Aisheng 	mdelay(1);
11290322191eSDong Aisheng 
11300ac4f496SHaibo Chen 	/* IC suggest to reset USDHC before every tuning command */
11310ac4f496SHaibo Chen 	esdhc_clrset_le(host, 0xff, SDHCI_RESET_ALL, SDHCI_SOFTWARE_RESET);
11320ac4f496SHaibo Chen 	ret = readb_poll_timeout(host->ioaddr + SDHCI_SOFTWARE_RESET, sw_rst,
11330ac4f496SHaibo Chen 				!(sw_rst & SDHCI_RESET_ALL), 10, 100);
11340ac4f496SHaibo Chen 	if (ret == -ETIMEDOUT)
11350ac4f496SHaibo Chen 		dev_warn(mmc_dev(host->mmc),
11360ac4f496SHaibo Chen 		"warning! RESET_ALL never complete before sending tuning command\n");
11370ac4f496SHaibo Chen 
11380322191eSDong Aisheng 	reg = readl(host->ioaddr + ESDHC_MIX_CTRL);
11390322191eSDong Aisheng 	reg |= ESDHC_MIX_CTRL_EXE_TUNE | ESDHC_MIX_CTRL_SMPCLK_SEL |
11400322191eSDong Aisheng 			ESDHC_MIX_CTRL_FBCLK_SEL;
11410322191eSDong Aisheng 	writel(reg, host->ioaddr + ESDHC_MIX_CTRL);
11420322191eSDong Aisheng 	writel(val << 8, host->ioaddr + ESDHC_TUNE_CTRL_STATUS);
11430322191eSDong Aisheng 	dev_dbg(mmc_dev(host->mmc),
1144d04f8d5bSBenoît Thébaudeau 		"tuning with delay 0x%x ESDHC_TUNE_CTRL_STATUS 0x%x\n",
11450322191eSDong Aisheng 			val, readl(host->ioaddr + ESDHC_TUNE_CTRL_STATUS));
11460322191eSDong Aisheng }
11470322191eSDong Aisheng 
esdhc_post_tuning(struct sdhci_host * host)11480322191eSDong Aisheng static void esdhc_post_tuning(struct sdhci_host *host)
11490322191eSDong Aisheng {
11500322191eSDong Aisheng 	u32 reg;
11510322191eSDong Aisheng 
11520322191eSDong Aisheng 	reg = readl(host->ioaddr + ESDHC_MIX_CTRL);
11530322191eSDong Aisheng 	reg &= ~ESDHC_MIX_CTRL_EXE_TUNE;
11540322191eSDong Aisheng 	writel(reg, host->ioaddr + ESDHC_MIX_CTRL);
11550322191eSDong Aisheng }
11560322191eSDong Aisheng 
esdhc_executing_tuning(struct sdhci_host * host,u32 opcode)11570322191eSDong Aisheng static int esdhc_executing_tuning(struct sdhci_host *host, u32 opcode)
11580322191eSDong Aisheng {
11590322191eSDong Aisheng 	int min, max, avg, ret;
11600322191eSDong Aisheng 
11610322191eSDong Aisheng 	/* find the mininum delay first which can pass tuning */
11620322191eSDong Aisheng 	min = ESDHC_TUNE_CTRL_MIN;
11630322191eSDong Aisheng 	while (min < ESDHC_TUNE_CTRL_MAX) {
11640322191eSDong Aisheng 		esdhc_prepare_tuning(host, min);
11659979dbe5SChaotian Jing 		if (!mmc_send_tuning(host->mmc, opcode, NULL))
11660322191eSDong Aisheng 			break;
11670322191eSDong Aisheng 		min += ESDHC_TUNE_CTRL_STEP;
11680322191eSDong Aisheng 	}
11690322191eSDong Aisheng 
11700322191eSDong Aisheng 	/* find the maxinum delay which can not pass tuning */
11710322191eSDong Aisheng 	max = min + ESDHC_TUNE_CTRL_STEP;
11720322191eSDong Aisheng 	while (max < ESDHC_TUNE_CTRL_MAX) {
11730322191eSDong Aisheng 		esdhc_prepare_tuning(host, max);
11749979dbe5SChaotian Jing 		if (mmc_send_tuning(host->mmc, opcode, NULL)) {
11750322191eSDong Aisheng 			max -= ESDHC_TUNE_CTRL_STEP;
11760322191eSDong Aisheng 			break;
11770322191eSDong Aisheng 		}
11780322191eSDong Aisheng 		max += ESDHC_TUNE_CTRL_STEP;
11790322191eSDong Aisheng 	}
11800322191eSDong Aisheng 
11810322191eSDong Aisheng 	/* use average delay to get the best timing */
11820322191eSDong Aisheng 	avg = (min + max) / 2;
11830322191eSDong Aisheng 	esdhc_prepare_tuning(host, avg);
11849979dbe5SChaotian Jing 	ret = mmc_send_tuning(host->mmc, opcode, NULL);
11850322191eSDong Aisheng 	esdhc_post_tuning(host);
11860322191eSDong Aisheng 
1187d04f8d5bSBenoît Thébaudeau 	dev_dbg(mmc_dev(host->mmc), "tuning %s at 0x%x ret %d\n",
11880322191eSDong Aisheng 		ret ? "failed" : "passed", avg, ret);
11890322191eSDong Aisheng 
11900322191eSDong Aisheng 	return ret;
11910322191eSDong Aisheng }
11920322191eSDong Aisheng 
esdhc_hs400_enhanced_strobe(struct mmc_host * mmc,struct mmc_ios * ios)1193029e2476SBOUGH CHEN static void esdhc_hs400_enhanced_strobe(struct mmc_host *mmc, struct mmc_ios *ios)
1194029e2476SBOUGH CHEN {
1195029e2476SBOUGH CHEN 	struct sdhci_host *host = mmc_priv(mmc);
1196029e2476SBOUGH CHEN 	u32 m;
1197029e2476SBOUGH CHEN 
1198029e2476SBOUGH CHEN 	m = readl(host->ioaddr + ESDHC_MIX_CTRL);
1199029e2476SBOUGH CHEN 	if (ios->enhanced_strobe)
1200029e2476SBOUGH CHEN 		m |= ESDHC_MIX_CTRL_HS400_ES_EN;
1201029e2476SBOUGH CHEN 	else
1202029e2476SBOUGH CHEN 		m &= ~ESDHC_MIX_CTRL_HS400_ES_EN;
1203029e2476SBOUGH CHEN 	writel(m, host->ioaddr + ESDHC_MIX_CTRL);
1204029e2476SBOUGH CHEN }
1205029e2476SBOUGH CHEN 
esdhc_change_pinstate(struct sdhci_host * host,unsigned int uhs)1206ad93220dSDong Aisheng static int esdhc_change_pinstate(struct sdhci_host *host,
1207ad93220dSDong Aisheng 						unsigned int uhs)
1208ad93220dSDong Aisheng {
1209ad93220dSDong Aisheng 	struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
1210070e6d3fSJisheng Zhang 	struct pltfm_imx_data *imx_data = sdhci_pltfm_priv(pltfm_host);
1211ad93220dSDong Aisheng 	struct pinctrl_state *pinctrl;
1212ad93220dSDong Aisheng 
1213ad93220dSDong Aisheng 	dev_dbg(mmc_dev(host->mmc), "change pinctrl state for uhs %d\n", uhs);
1214ad93220dSDong Aisheng 
1215ad93220dSDong Aisheng 	if (IS_ERR(imx_data->pinctrl) ||
1216ad93220dSDong Aisheng 		IS_ERR(imx_data->pins_100mhz) ||
1217ad93220dSDong Aisheng 		IS_ERR(imx_data->pins_200mhz))
1218ad93220dSDong Aisheng 		return -EINVAL;
1219ad93220dSDong Aisheng 
1220ad93220dSDong Aisheng 	switch (uhs) {
1221ad93220dSDong Aisheng 	case MMC_TIMING_UHS_SDR50:
12229f327845SHaibo Chen 	case MMC_TIMING_UHS_DDR50:
1223ad93220dSDong Aisheng 		pinctrl = imx_data->pins_100mhz;
1224ad93220dSDong Aisheng 		break;
1225ad93220dSDong Aisheng 	case MMC_TIMING_UHS_SDR104:
1226429a5b45SDong Aisheng 	case MMC_TIMING_MMC_HS200:
122728b07674SHaibo Chen 	case MMC_TIMING_MMC_HS400:
1228ad93220dSDong Aisheng 		pinctrl = imx_data->pins_200mhz;
1229ad93220dSDong Aisheng 		break;
1230ad93220dSDong Aisheng 	default:
1231ad93220dSDong Aisheng 		/* back to default state for other legacy timing */
12322480b720SUlf Hansson 		return pinctrl_select_default_state(mmc_dev(host->mmc));
1233ad93220dSDong Aisheng 	}
1234ad93220dSDong Aisheng 
1235ad93220dSDong Aisheng 	return pinctrl_select_state(imx_data->pinctrl, pinctrl);
1236ad93220dSDong Aisheng }
1237ad93220dSDong Aisheng 
123828b07674SHaibo Chen /*
1239d04f8d5bSBenoît Thébaudeau  * For HS400 eMMC, there is a data_strobe line. This signal is generated
124028b07674SHaibo Chen  * by the device and used for data output and CRC status response output
124128b07674SHaibo Chen  * in HS400 mode. The frequency of this signal follows the frequency of
1242d04f8d5bSBenoît Thébaudeau  * CLK generated by host. The host receives the data which is aligned to the
124328b07674SHaibo Chen  * edge of data_strobe line. Due to the time delay between CLK line and
124428b07674SHaibo Chen  * data_strobe line, if the delay time is larger than one clock cycle,
1245d04f8d5bSBenoît Thébaudeau  * then CLK and data_strobe line will be misaligned, read error shows up.
124628b07674SHaibo Chen  */
esdhc_set_strobe_dll(struct sdhci_host * host)124728b07674SHaibo Chen static void esdhc_set_strobe_dll(struct sdhci_host *host)
124828b07674SHaibo Chen {
12495bd2acdcSHaibo Chen 	struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
12505bd2acdcSHaibo Chen 	struct pltfm_imx_data *imx_data = sdhci_pltfm_priv(pltfm_host);
12515bd2acdcSHaibo Chen 	u32 strobe_delay;
125228b07674SHaibo Chen 	u32 v;
1253373e800bSHaibo Chen 	int ret;
125428b07674SHaibo Chen 
12557ac6da26SDong Aisheng 	/* disable clock before enabling strobe dll */
12567ac6da26SDong Aisheng 	writel(readl(host->ioaddr + ESDHC_VENDOR_SPEC) &
12577ac6da26SDong Aisheng 		~ESDHC_VENDOR_SPEC_FRC_SDCLK_ON,
12587ac6da26SDong Aisheng 		host->ioaddr + ESDHC_VENDOR_SPEC);
1259f581e909SHaibo Chen 	esdhc_wait_for_card_clock_gate_off(host);
12607ac6da26SDong Aisheng 
126128b07674SHaibo Chen 	/* force a reset on strobe dll */
126228b07674SHaibo Chen 	writel(ESDHC_STROBE_DLL_CTRL_RESET,
126328b07674SHaibo Chen 		host->ioaddr + ESDHC_STROBE_DLL_CTRL);
12642eaf5a53SBOUGH CHEN 	/* clear the reset bit on strobe dll before any setting */
12652eaf5a53SBOUGH CHEN 	writel(0, host->ioaddr + ESDHC_STROBE_DLL_CTRL);
12662eaf5a53SBOUGH CHEN 
126728b07674SHaibo Chen 	/*
126828b07674SHaibo Chen 	 * enable strobe dll ctrl and adjust the delay target
126928b07674SHaibo Chen 	 * for the uSDHC loopback read clock
127028b07674SHaibo Chen 	 */
12715bd2acdcSHaibo Chen 	if (imx_data->boarddata.strobe_dll_delay_target)
12725bd2acdcSHaibo Chen 		strobe_delay = imx_data->boarddata.strobe_dll_delay_target;
12735bd2acdcSHaibo Chen 	else
12745bd2acdcSHaibo Chen 		strobe_delay = ESDHC_STROBE_DLL_CTRL_SLV_DLY_TARGET_DEFAULT;
127528b07674SHaibo Chen 	v = ESDHC_STROBE_DLL_CTRL_ENABLE |
12762eaf5a53SBOUGH CHEN 		ESDHC_STROBE_DLL_CTRL_SLV_UPDATE_INT_DEFAULT |
12775bd2acdcSHaibo Chen 		(strobe_delay << ESDHC_STROBE_DLL_CTRL_SLV_DLY_TARGET_SHIFT);
127828b07674SHaibo Chen 	writel(v, host->ioaddr + ESDHC_STROBE_DLL_CTRL);
1279373e800bSHaibo Chen 
1280373e800bSHaibo Chen 	/* wait max 50us to get the REF/SLV lock */
1281373e800bSHaibo Chen 	ret = readl_poll_timeout(host->ioaddr + ESDHC_STROBE_DLL_STATUS, v,
1282373e800bSHaibo Chen 		((v & ESDHC_STROBE_DLL_STS_REF_LOCK) && (v & ESDHC_STROBE_DLL_STS_SLV_LOCK)), 1, 50);
1283373e800bSHaibo Chen 	if (ret == -ETIMEDOUT)
128428b07674SHaibo Chen 		dev_warn(mmc_dev(host->mmc),
1285373e800bSHaibo Chen 		"warning! HS400 strobe DLL status REF/SLV not lock in 50us, STROBE DLL status is %x!\n", v);
128628b07674SHaibo Chen }
128728b07674SHaibo Chen 
esdhc_set_uhs_signaling(struct sdhci_host * host,unsigned timing)1288850a29b8SRussell King static void esdhc_set_uhs_signaling(struct sdhci_host *host, unsigned timing)
1289ad93220dSDong Aisheng {
129028b07674SHaibo Chen 	u32 m;
1291ad93220dSDong Aisheng 	struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
1292070e6d3fSJisheng Zhang 	struct pltfm_imx_data *imx_data = sdhci_pltfm_priv(pltfm_host);
1293602519b2SDong Aisheng 	struct esdhc_platform_data *boarddata = &imx_data->boarddata;
1294ad93220dSDong Aisheng 
129528b07674SHaibo Chen 	/* disable ddr mode and disable HS400 mode */
129628b07674SHaibo Chen 	m = readl(host->ioaddr + ESDHC_MIX_CTRL);
129728b07674SHaibo Chen 	m &= ~(ESDHC_MIX_CTRL_DDREN | ESDHC_MIX_CTRL_HS400_EN);
129828b07674SHaibo Chen 	imx_data->is_ddr = 0;
129928b07674SHaibo Chen 
1300850a29b8SRussell King 	switch (timing) {
1301ad93220dSDong Aisheng 	case MMC_TIMING_UHS_SDR12:
1302ad93220dSDong Aisheng 	case MMC_TIMING_UHS_SDR25:
1303ad93220dSDong Aisheng 	case MMC_TIMING_UHS_SDR50:
1304ad93220dSDong Aisheng 	case MMC_TIMING_UHS_SDR104:
1305de0a0decSBOUGH CHEN 	case MMC_TIMING_MMC_HS:
1306429a5b45SDong Aisheng 	case MMC_TIMING_MMC_HS200:
130728b07674SHaibo Chen 		writel(m, host->ioaddr + ESDHC_MIX_CTRL);
1308ad93220dSDong Aisheng 		break;
1309ad93220dSDong Aisheng 	case MMC_TIMING_UHS_DDR50:
131069f5bf38SAisheng Dong 	case MMC_TIMING_MMC_DDR52:
131128b07674SHaibo Chen 		m |= ESDHC_MIX_CTRL_DDREN;
131228b07674SHaibo Chen 		writel(m, host->ioaddr + ESDHC_MIX_CTRL);
1313de5bdbffSDong Aisheng 		imx_data->is_ddr = 1;
1314602519b2SDong Aisheng 		if (boarddata->delay_line) {
1315602519b2SDong Aisheng 			u32 v;
1316602519b2SDong Aisheng 			v = boarddata->delay_line <<
1317602519b2SDong Aisheng 				ESDHC_DLL_OVERRIDE_VAL_SHIFT |
1318602519b2SDong Aisheng 				(1 << ESDHC_DLL_OVERRIDE_EN_SHIFT);
1319602519b2SDong Aisheng 			if (is_imx53_esdhc(imx_data))
1320602519b2SDong Aisheng 				v <<= 1;
1321602519b2SDong Aisheng 			writel(v, host->ioaddr + ESDHC_DLL_CTRL);
1322602519b2SDong Aisheng 		}
1323ad93220dSDong Aisheng 		break;
132428b07674SHaibo Chen 	case MMC_TIMING_MMC_HS400:
132528b07674SHaibo Chen 		m |= ESDHC_MIX_CTRL_DDREN | ESDHC_MIX_CTRL_HS400_EN;
132628b07674SHaibo Chen 		writel(m, host->ioaddr + ESDHC_MIX_CTRL);
132728b07674SHaibo Chen 		imx_data->is_ddr = 1;
13287ac6da26SDong Aisheng 		/* update clock after enable DDR for strobe DLL lock */
13297ac6da26SDong Aisheng 		host->ops->set_clock(host, host->clock);
133028b07674SHaibo Chen 		esdhc_set_strobe_dll(host);
133128b07674SHaibo Chen 		break;
1332d9370424SHaibo Chen 	case MMC_TIMING_LEGACY:
1333d9370424SHaibo Chen 	default:
1334d9370424SHaibo Chen 		esdhc_reset_tuning(host);
1335d9370424SHaibo Chen 		break;
1336ad93220dSDong Aisheng 	}
1337ad93220dSDong Aisheng 
1338850a29b8SRussell King 	esdhc_change_pinstate(host, timing);
1339ad93220dSDong Aisheng }
1340ad93220dSDong Aisheng 
esdhc_reset(struct sdhci_host * host,u8 mask)13410718e59aSRussell King static void esdhc_reset(struct sdhci_host *host, u8 mask)
13420718e59aSRussell King {
1343fb1dec44SBrian Norris 	sdhci_and_cqhci_reset(host, mask);
13440718e59aSRussell King 
13450718e59aSRussell King 	sdhci_writel(host, host->ier, SDHCI_INT_ENABLE);
13460718e59aSRussell King 	sdhci_writel(host, host->ier, SDHCI_SIGNAL_ENABLE);
13470718e59aSRussell King }
13480718e59aSRussell King 
esdhc_get_max_timeout_count(struct sdhci_host * host)134910fd0ad9SAisheng Dong static unsigned int esdhc_get_max_timeout_count(struct sdhci_host *host)
135010fd0ad9SAisheng Dong {
135110fd0ad9SAisheng Dong 	struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
1352070e6d3fSJisheng Zhang 	struct pltfm_imx_data *imx_data = sdhci_pltfm_priv(pltfm_host);
135310fd0ad9SAisheng Dong 
1354d04f8d5bSBenoît Thébaudeau 	/* Doc Erratum: the uSDHC actual maximum timeout count is 1 << 29 */
13552fb0b02bSHaibo Chen 	return esdhc_is_usdhc(imx_data) ? 1 << 29 : 1 << 27;
135610fd0ad9SAisheng Dong }
135710fd0ad9SAisheng Dong 
esdhc_set_timeout(struct sdhci_host * host,struct mmc_command * cmd)1358e33eb8e2SAisheng Dong static void esdhc_set_timeout(struct sdhci_host *host, struct mmc_command *cmd)
1359e33eb8e2SAisheng Dong {
1360e33eb8e2SAisheng Dong 	struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
1361070e6d3fSJisheng Zhang 	struct pltfm_imx_data *imx_data = sdhci_pltfm_priv(pltfm_host);
1362e33eb8e2SAisheng Dong 
1363e33eb8e2SAisheng Dong 	/* use maximum timeout counter */
1364a215186dSHaibo Chen 	esdhc_clrset_le(host, ESDHC_SYS_CTRL_DTOCV_MASK,
1365a215186dSHaibo Chen 			esdhc_is_usdhc(imx_data) ? 0xF : 0xE,
1366e33eb8e2SAisheng Dong 			SDHCI_TIMEOUT_CONTROL);
1367e33eb8e2SAisheng Dong }
1368e33eb8e2SAisheng Dong 
esdhc_cqhci_irq(struct sdhci_host * host,u32 intmask)1369bb6e3581SBOUGH CHEN static u32 esdhc_cqhci_irq(struct sdhci_host *host, u32 intmask)
1370bb6e3581SBOUGH CHEN {
1371bb6e3581SBOUGH CHEN 	int cmd_error = 0;
1372bb6e3581SBOUGH CHEN 	int data_error = 0;
1373bb6e3581SBOUGH CHEN 
1374bb6e3581SBOUGH CHEN 	if (!sdhci_cqe_irq(host, intmask, &cmd_error, &data_error))
1375bb6e3581SBOUGH CHEN 		return intmask;
1376bb6e3581SBOUGH CHEN 
1377bb6e3581SBOUGH CHEN 	cqhci_irq(host->mmc, intmask, cmd_error, data_error);
1378bb6e3581SBOUGH CHEN 
1379bb6e3581SBOUGH CHEN 	return 0;
1380bb6e3581SBOUGH CHEN }
1381bb6e3581SBOUGH CHEN 
13826e9fd28eSDong Aisheng static struct sdhci_ops sdhci_esdhc_ops = {
1383e149860dSRichard Zhu 	.read_l = esdhc_readl_le,
13840c6d49ceSWolfram Sang 	.read_w = esdhc_readw_le,
138577da3da0SAaron Brice 	.read_b = esdhc_readb_le,
1386e149860dSRichard Zhu 	.write_l = esdhc_writel_le,
13870c6d49ceSWolfram Sang 	.write_w = esdhc_writew_le,
13880c6d49ceSWolfram Sang 	.write_b = esdhc_writeb_le,
13898ba9580aSLucas Stach 	.set_clock = esdhc_pltfm_set_clock,
13900ddf03c9SLucas Stach 	.get_max_clock = esdhc_pltfm_get_max_clock,
13910c6d49ceSWolfram Sang 	.get_min_clock = esdhc_pltfm_get_min_clock,
139210fd0ad9SAisheng Dong 	.get_max_timeout_count = esdhc_get_max_timeout_count,
1393913413c3SShawn Guo 	.get_ro = esdhc_pltfm_get_ro,
1394e33eb8e2SAisheng Dong 	.set_timeout = esdhc_set_timeout,
13952317f56cSRussell King 	.set_bus_width = esdhc_pltfm_set_bus_width,
1396ad93220dSDong Aisheng 	.set_uhs_signaling = esdhc_set_uhs_signaling,
13970718e59aSRussell King 	.reset = esdhc_reset,
1398bb6e3581SBOUGH CHEN 	.irq = esdhc_cqhci_irq,
13993722c74cSHaibo Chen 	.dump_vendor_regs = esdhc_dump_debug_regs,
14000c6d49ceSWolfram Sang };
14010c6d49ceSWolfram Sang 
14021db5eebfSLars-Peter Clausen static const struct sdhci_pltfm_data sdhci_esdhc_imx_pdata = {
140397e4ba6aSRichard Zhu 	.quirks = ESDHC_DEFAULT_QUIRKS | SDHCI_QUIRK_NO_HISPD_BIT
140497e4ba6aSRichard Zhu 			| SDHCI_QUIRK_NO_ENDATTR_IN_NOPDESC
140597e4ba6aSRichard Zhu 			| SDHCI_QUIRK_BROKEN_ADMA_ZEROLEN_DESC
140685d6509dSShawn Guo 			| SDHCI_QUIRK_BROKEN_CARD_DETECTION,
140785d6509dSShawn Guo 	.ops = &sdhci_esdhc_ops,
140885d6509dSShawn Guo };
140985d6509dSShawn Guo 
sdhci_esdhc_imx_hwinit(struct sdhci_host * host)1410f3f5cf3dSDong Aisheng static void sdhci_esdhc_imx_hwinit(struct sdhci_host *host)
1411f3f5cf3dSDong Aisheng {
1412f3f5cf3dSDong Aisheng 	struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
1413f3f5cf3dSDong Aisheng 	struct pltfm_imx_data *imx_data = sdhci_pltfm_priv(pltfm_host);
1414982cf37dSHaibo Chen 	struct cqhci_host *cq_host = host->mmc->cqe_private;
14151e336aa0SHaibo Chen 	u32 tmp;
1416f3f5cf3dSDong Aisheng 
1417f3f5cf3dSDong Aisheng 	if (esdhc_is_usdhc(imx_data)) {
1418f3f5cf3dSDong Aisheng 		/*
1419f3f5cf3dSDong Aisheng 		 * The imx6q ROM code will change the default watermark
1420f3f5cf3dSDong Aisheng 		 * level setting to something insane.  Change it back here.
1421f3f5cf3dSDong Aisheng 		 */
1422f3f5cf3dSDong Aisheng 		writel(ESDHC_WTMK_DEFAULT_VAL, host->ioaddr + ESDHC_WTMK_LVL);
1423f3f5cf3dSDong Aisheng 
1424f3f5cf3dSDong Aisheng 		/*
1425f3f5cf3dSDong Aisheng 		 * ROM code will change the bit burst_length_enable setting
1426d04f8d5bSBenoît Thébaudeau 		 * to zero if this usdhc is chosen to boot system. Change
1427f3f5cf3dSDong Aisheng 		 * it back here, otherwise it will impact the performance a
1428f3f5cf3dSDong Aisheng 		 * lot. This bit is used to enable/disable the burst length
1429d04f8d5bSBenoît Thébaudeau 		 * for the external AHB2AXI bridge. It's useful especially
1430f3f5cf3dSDong Aisheng 		 * for INCR transfer because without burst length indicator,
1431f3f5cf3dSDong Aisheng 		 * the AHB2AXI bridge does not know the burst length in
1432f3f5cf3dSDong Aisheng 		 * advance. And without burst length indicator, AHB INCR
1433f3f5cf3dSDong Aisheng 		 * transfer can only be converted to singles on the AXI side.
1434f3f5cf3dSDong Aisheng 		 */
1435f3f5cf3dSDong Aisheng 		writel(readl(host->ioaddr + SDHCI_HOST_CONTROL)
1436f3f5cf3dSDong Aisheng 			| ESDHC_BURST_LEN_EN_INCR,
1437f3f5cf3dSDong Aisheng 			host->ioaddr + SDHCI_HOST_CONTROL);
1438e30be063SBOUGH CHEN 
1439f3f5cf3dSDong Aisheng 		/*
1440d04f8d5bSBenoît Thébaudeau 		 * erratum ESDHC_FLAG_ERR004536 fix for MX6Q TO1.2 and MX6DL
1441f3f5cf3dSDong Aisheng 		 * TO1.1, it's harmless for MX6SL
1442f3f5cf3dSDong Aisheng 		 */
14435c4f0062SChester Lin 		if (!(imx_data->socdata->flags & ESDHC_FLAG_SKIP_ERR004536)) {
1444e30be063SBOUGH CHEN 			writel(readl(host->ioaddr + 0x6c) & ~BIT(7),
1445f3f5cf3dSDong Aisheng 				host->ioaddr + 0x6c);
14465c4f0062SChester Lin 		}
1447f3f5cf3dSDong Aisheng 
1448f3f5cf3dSDong Aisheng 		/* disable DLL_CTRL delay line settings */
1449f3f5cf3dSDong Aisheng 		writel(0x0, host->ioaddr + ESDHC_DLL_CTRL);
14502b16cf32SDong Aisheng 
1451bcdb5301SBOUGH CHEN 		/*
1452bcdb5301SBOUGH CHEN 		 * For the case of command with busy, if set the bit
1453bcdb5301SBOUGH CHEN 		 * ESDHC_VEND_SPEC2_EN_BUSY_IRQ, USDHC will generate a
1454bcdb5301SBOUGH CHEN 		 * transfer complete interrupt when busy is deasserted.
1455bcdb5301SBOUGH CHEN 		 * When CQHCI use DCMD to send a CMD need R1b respons,
1456bcdb5301SBOUGH CHEN 		 * CQHCI require to set ESDHC_VEND_SPEC2_EN_BUSY_IRQ,
1457bcdb5301SBOUGH CHEN 		 * otherwise DCMD will always meet timeout waiting for
1458bcdb5301SBOUGH CHEN 		 * hardware interrupt issue.
1459bcdb5301SBOUGH CHEN 		 */
1460bcdb5301SBOUGH CHEN 		if (imx_data->socdata->flags & ESDHC_FLAG_CQHCI) {
1461bcdb5301SBOUGH CHEN 			tmp = readl(host->ioaddr + ESDHC_VEND_SPEC2);
1462bcdb5301SBOUGH CHEN 			tmp |= ESDHC_VEND_SPEC2_EN_BUSY_IRQ;
1463bcdb5301SBOUGH CHEN 			writel(tmp, host->ioaddr + ESDHC_VEND_SPEC2);
1464bcdb5301SBOUGH CHEN 
1465bcdb5301SBOUGH CHEN 			host->quirks &= ~SDHCI_QUIRK_NO_BUSY_IRQ;
1466bcdb5301SBOUGH CHEN 		}
1467bcdb5301SBOUGH CHEN 
14682b16cf32SDong Aisheng 		if (imx_data->socdata->flags & ESDHC_FLAG_STD_TUNING) {
14692b16cf32SDong Aisheng 			tmp = readl(host->ioaddr + ESDHC_TUNING_CTRL);
14701e336aa0SHaibo Chen 			tmp |= ESDHC_STD_TUNING_EN;
14711e336aa0SHaibo Chen 
14721e336aa0SHaibo Chen 			/*
14731e336aa0SHaibo Chen 			 * ROM code or bootloader may config the start tap
14741e336aa0SHaibo Chen 			 * and step, unmask them first.
14751e336aa0SHaibo Chen 			 */
14761e336aa0SHaibo Chen 			tmp &= ~(ESDHC_TUNING_START_TAP_MASK | ESDHC_TUNING_STEP_MASK);
14771e336aa0SHaibo Chen 			if (imx_data->boarddata.tuning_start_tap)
14782b16cf32SDong Aisheng 				tmp |= imx_data->boarddata.tuning_start_tap;
14791e336aa0SHaibo Chen 			else
14801e336aa0SHaibo Chen 				tmp |= ESDHC_TUNING_START_TAP_DEFAULT;
14812b16cf32SDong Aisheng 
14822b16cf32SDong Aisheng 			if (imx_data->boarddata.tuning_step) {
14832b16cf32SDong Aisheng 				tmp |= imx_data->boarddata.tuning_step
14842b16cf32SDong Aisheng 					<< ESDHC_TUNING_STEP_SHIFT;
14851e336aa0SHaibo Chen 			} else {
14861e336aa0SHaibo Chen 				tmp |= ESDHC_TUNING_STEP_DEFAULT
14871e336aa0SHaibo Chen 					<< ESDHC_TUNING_STEP_SHIFT;
14882b16cf32SDong Aisheng 			}
148916e40e5bSHaibo Chen 
149016e40e5bSHaibo Chen 			/* Disable the CMD CRC check for tuning, if not, need to
149116e40e5bSHaibo Chen 			 * add some delay after every tuning command, because
149216e40e5bSHaibo Chen 			 * hardware standard tuning logic will directly go to next
149316e40e5bSHaibo Chen 			 * step once it detect the CMD CRC error, will not wait for
149416e40e5bSHaibo Chen 			 * the card side to finally send out the tuning data, trigger
149516e40e5bSHaibo Chen 			 * the buffer read ready interrupt immediately. If usdhc send
149616e40e5bSHaibo Chen 			 * the next tuning command some eMMC card will stuck, can't
149716e40e5bSHaibo Chen 			 * response, block the tuning procedure or the first command
149816e40e5bSHaibo Chen 			 * after the whole tuning procedure always can't get any response.
149916e40e5bSHaibo Chen 			 */
150016e40e5bSHaibo Chen 			tmp |= ESDHC_TUNING_CMD_CRC_CHECK_DISABLE;
15012b16cf32SDong Aisheng 			writel(tmp, host->ioaddr + ESDHC_TUNING_CTRL);
1502a98c557eSBOUGH CHEN 		} else if (imx_data->socdata->flags & ESDHC_FLAG_MAN_TUNING) {
1503a98c557eSBOUGH CHEN 			/*
1504a98c557eSBOUGH CHEN 			 * ESDHC_STD_TUNING_EN may be configed in bootloader
1505a98c557eSBOUGH CHEN 			 * or ROM code, so clear this bit here to make sure
1506a98c557eSBOUGH CHEN 			 * the manual tuning can work.
1507a98c557eSBOUGH CHEN 			 */
1508a98c557eSBOUGH CHEN 			tmp = readl(host->ioaddr + ESDHC_TUNING_CTRL);
1509a98c557eSBOUGH CHEN 			tmp &= ~ESDHC_STD_TUNING_EN;
1510a98c557eSBOUGH CHEN 			writel(tmp, host->ioaddr + ESDHC_TUNING_CTRL);
15112b16cf32SDong Aisheng 		}
1512982cf37dSHaibo Chen 
1513982cf37dSHaibo Chen 		/*
1514982cf37dSHaibo Chen 		 * On i.MX8MM, we are running Dual Linux OS, with 1st Linux using SD Card
15151ad0dcb9Swangjianli 		 * as rootfs storage, 2nd Linux using eMMC as rootfs storage. We let
1516982cf37dSHaibo Chen 		 * the 1st linux configure power/clock for the 2nd Linux.
1517982cf37dSHaibo Chen 		 *
1518982cf37dSHaibo Chen 		 * When the 2nd Linux is booting into rootfs stage, we let the 1st Linux
1519982cf37dSHaibo Chen 		 * to destroy the 2nd linux, then restart the 2nd linux, we met SDHCI dump.
1520982cf37dSHaibo Chen 		 * After we clear the pending interrupt and halt CQCTL, issue gone.
1521982cf37dSHaibo Chen 		 */
1522982cf37dSHaibo Chen 		if (cq_host) {
1523982cf37dSHaibo Chen 			tmp = cqhci_readl(cq_host, CQHCI_IS);
1524982cf37dSHaibo Chen 			cqhci_writel(cq_host, tmp, CQHCI_IS);
1525982cf37dSHaibo Chen 			cqhci_writel(cq_host, CQHCI_HALT, CQHCI_CTL);
1526982cf37dSHaibo Chen 		}
1527f3f5cf3dSDong Aisheng 	}
1528f3f5cf3dSDong Aisheng }
1529f3f5cf3dSDong Aisheng 
esdhc_cqe_enable(struct mmc_host * mmc)1530bb6e3581SBOUGH CHEN static void esdhc_cqe_enable(struct mmc_host *mmc)
1531bb6e3581SBOUGH CHEN {
1532bb6e3581SBOUGH CHEN 	struct sdhci_host *host = mmc_priv(mmc);
153385236d2bSBOUGH CHEN 	struct cqhci_host *cq_host = mmc->cqe_private;
1534bb6e3581SBOUGH CHEN 	u32 reg;
1535bb6e3581SBOUGH CHEN 	u16 mode;
1536bb6e3581SBOUGH CHEN 	int count = 10;
1537bb6e3581SBOUGH CHEN 
1538bb6e3581SBOUGH CHEN 	/*
1539bb6e3581SBOUGH CHEN 	 * CQE gets stuck if it sees Buffer Read Enable bit set, which can be
1540bb6e3581SBOUGH CHEN 	 * the case after tuning, so ensure the buffer is drained.
1541bb6e3581SBOUGH CHEN 	 */
1542bb6e3581SBOUGH CHEN 	reg = sdhci_readl(host, SDHCI_PRESENT_STATE);
1543bb6e3581SBOUGH CHEN 	while (reg & SDHCI_DATA_AVAILABLE) {
1544bb6e3581SBOUGH CHEN 		sdhci_readl(host, SDHCI_BUFFER);
1545bb6e3581SBOUGH CHEN 		reg = sdhci_readl(host, SDHCI_PRESENT_STATE);
1546bb6e3581SBOUGH CHEN 		if (count-- == 0) {
1547bb6e3581SBOUGH CHEN 			dev_warn(mmc_dev(host->mmc),
1548bb6e3581SBOUGH CHEN 				"CQE may get stuck because the Buffer Read Enable bit is set\n");
1549bb6e3581SBOUGH CHEN 			break;
1550bb6e3581SBOUGH CHEN 		}
1551bb6e3581SBOUGH CHEN 		mdelay(1);
1552bb6e3581SBOUGH CHEN 	}
1553bb6e3581SBOUGH CHEN 
1554bb6e3581SBOUGH CHEN 	/*
1555bb6e3581SBOUGH CHEN 	 * Runtime resume will reset the entire host controller, which
1556bb6e3581SBOUGH CHEN 	 * will also clear the DMAEN/BCEN of register ESDHC_MIX_CTRL.
1557bb6e3581SBOUGH CHEN 	 * Here set DMAEN and BCEN when enable CMDQ.
1558bb6e3581SBOUGH CHEN 	 */
1559bb6e3581SBOUGH CHEN 	mode = sdhci_readw(host, SDHCI_TRANSFER_MODE);
1560bb6e3581SBOUGH CHEN 	if (host->flags & SDHCI_REQ_USE_DMA)
1561bb6e3581SBOUGH CHEN 		mode |= SDHCI_TRNS_DMA;
1562bb6e3581SBOUGH CHEN 	if (!(host->quirks2 & SDHCI_QUIRK2_SUPPORT_SINGLE))
1563bb6e3581SBOUGH CHEN 		mode |= SDHCI_TRNS_BLK_CNT_EN;
1564bb6e3581SBOUGH CHEN 	sdhci_writew(host, mode, SDHCI_TRANSFER_MODE);
1565bb6e3581SBOUGH CHEN 
156685236d2bSBOUGH CHEN 	/*
156785236d2bSBOUGH CHEN 	 * Though Runtime resume reset the entire host controller,
156885236d2bSBOUGH CHEN 	 * but do not impact the CQHCI side, need to clear the
156985236d2bSBOUGH CHEN 	 * HALT bit, avoid CQHCI stuck in the first request when
157085236d2bSBOUGH CHEN 	 * system resume back.
157185236d2bSBOUGH CHEN 	 */
157285236d2bSBOUGH CHEN 	cqhci_writel(cq_host, 0, CQHCI_CTL);
1573a3cab1d2SSebastian Falbesoner 	if (cqhci_readl(cq_host, CQHCI_CTL) & CQHCI_HALT)
157485236d2bSBOUGH CHEN 		dev_err(mmc_dev(host->mmc),
157585236d2bSBOUGH CHEN 			"failed to exit halt state when enable CQE\n");
157685236d2bSBOUGH CHEN 
157785236d2bSBOUGH CHEN 
1578bb6e3581SBOUGH CHEN 	sdhci_cqe_enable(mmc);
1579bb6e3581SBOUGH CHEN }
1580bb6e3581SBOUGH CHEN 
esdhc_sdhci_dumpregs(struct mmc_host * mmc)1581bb6e3581SBOUGH CHEN static void esdhc_sdhci_dumpregs(struct mmc_host *mmc)
1582bb6e3581SBOUGH CHEN {
1583bb6e3581SBOUGH CHEN 	sdhci_dumpregs(mmc_priv(mmc));
1584bb6e3581SBOUGH CHEN }
1585bb6e3581SBOUGH CHEN 
1586bb6e3581SBOUGH CHEN static const struct cqhci_host_ops esdhc_cqhci_ops = {
1587bb6e3581SBOUGH CHEN 	.enable		= esdhc_cqe_enable,
1588bb6e3581SBOUGH CHEN 	.disable	= sdhci_cqe_disable,
1589bb6e3581SBOUGH CHEN 	.dumpregs	= esdhc_sdhci_dumpregs,
1590bb6e3581SBOUGH CHEN };
1591bb6e3581SBOUGH CHEN 
1592c3be1efdSBill Pemberton static int
sdhci_esdhc_imx_probe_dt(struct platform_device * pdev,struct sdhci_host * host,struct pltfm_imx_data * imx_data)1593abfafc2dSShawn Guo sdhci_esdhc_imx_probe_dt(struct platform_device *pdev,
159407bf2b54SSascha Hauer 			 struct sdhci_host *host,
159591fa4252SDong Aisheng 			 struct pltfm_imx_data *imx_data)
1596abfafc2dSShawn Guo {
1597abfafc2dSShawn Guo 	struct device_node *np = pdev->dev.of_node;
159891fa4252SDong Aisheng 	struct esdhc_platform_data *boarddata = &imx_data->boarddata;
15994800e87aSDong Aisheng 	int ret;
1600abfafc2dSShawn Guo 
1601ca6b5fe2SRob Herring 	if (of_property_read_bool(np, "fsl,wp-controller"))
1602abfafc2dSShawn Guo 		boarddata->wp_type = ESDHC_WP_CONTROLLER;
1603abfafc2dSShawn Guo 
160474ff81e1SLinus Walleij 	/*
160574ff81e1SLinus Walleij 	 * If we have this property, then activate WP check.
160674ff81e1SLinus Walleij 	 * Retrieveing and requesting the actual WP GPIO will happen
160774ff81e1SLinus Walleij 	 * in the call to mmc_of_parse().
160874ff81e1SLinus Walleij 	 */
160974ff81e1SLinus Walleij 	if (of_property_read_bool(np, "wp-gpios"))
1610abfafc2dSShawn Guo 		boarddata->wp_type = ESDHC_WP_GPIO;
1611abfafc2dSShawn Guo 
1612d407e30bSHaibo Chen 	of_property_read_u32(np, "fsl,tuning-step", &boarddata->tuning_step);
1613d87fc966SDong Aisheng 	of_property_read_u32(np, "fsl,tuning-start-tap",
1614d87fc966SDong Aisheng 			     &boarddata->tuning_start_tap);
1615d407e30bSHaibo Chen 
16165bd2acdcSHaibo Chen 	of_property_read_u32(np, "fsl,strobe-dll-delay-target",
16175bd2acdcSHaibo Chen 				&boarddata->strobe_dll_delay_target);
1618ca6b5fe2SRob Herring 	if (of_property_read_bool(np, "no-1-8-v"))
161986f495c5SStefan Agner 		host->quirks2 |= SDHCI_QUIRK2_NO_1_8_V;
1620ad93220dSDong Aisheng 
1621602519b2SDong Aisheng 	if (of_property_read_u32(np, "fsl,delay-line", &boarddata->delay_line))
1622602519b2SDong Aisheng 		boarddata->delay_line = 0;
1623602519b2SDong Aisheng 
16246dab809bSAndy Shevchenko 	mmc_of_parse_voltage(host->mmc, &host->ocr_mask);
162507bf2b54SSascha Hauer 
1626f410ee0aSPeng Fan 	if (esdhc_is_usdhc(imx_data) && !IS_ERR(imx_data->pinctrl)) {
162791fa4252SDong Aisheng 		imx_data->pins_100mhz = pinctrl_lookup_state(imx_data->pinctrl,
162891fa4252SDong Aisheng 						ESDHC_PINCTRL_STATE_100MHZ);
162991fa4252SDong Aisheng 		imx_data->pins_200mhz = pinctrl_lookup_state(imx_data->pinctrl,
163091fa4252SDong Aisheng 						ESDHC_PINCTRL_STATE_200MHZ);
163191fa4252SDong Aisheng 	}
163291fa4252SDong Aisheng 
163315064119SFabio Estevam 	/* call to generic mmc_of_parse to support additional capabilities */
16344800e87aSDong Aisheng 	ret = mmc_of_parse(host->mmc);
16354800e87aSDong Aisheng 	if (ret)
16364800e87aSDong Aisheng 		return ret;
16374800e87aSDong Aisheng 
163881dce149SHaibo Chen 	/* HS400/HS400ES require 8 bit bus */
163981dce149SHaibo Chen 	if (!(host->mmc->caps & MMC_CAP_8_BIT_DATA))
164081dce149SHaibo Chen 		host->mmc->caps2 &= ~(MMC_CAP2_HS400 | MMC_CAP2_HS400_ES);
164181dce149SHaibo Chen 
1642287980e4SArnd Bergmann 	if (mmc_gpio_get_cd(host->mmc) >= 0)
16434800e87aSDong Aisheng 		host->quirks &= ~SDHCI_QUIRK_BROKEN_CARD_DETECTION;
16444800e87aSDong Aisheng 
16454800e87aSDong Aisheng 	return 0;
1646abfafc2dSShawn Guo }
1647abfafc2dSShawn Guo 
sdhci_esdhc_imx_probe(struct platform_device * pdev)1648c3be1efdSBill Pemberton static int sdhci_esdhc_imx_probe(struct platform_device *pdev)
164995f25efeSWolfram Sang {
165085d6509dSShawn Guo 	struct sdhci_pltfm_host *pltfm_host;
165185d6509dSShawn Guo 	struct sdhci_host *host;
1652bb6e3581SBOUGH CHEN 	struct cqhci_host *cq_host;
16530c6d49ceSWolfram Sang 	int err;
1654e149860dSRichard Zhu 	struct pltfm_imx_data *imx_data;
165595f25efeSWolfram Sang 
1656070e6d3fSJisheng Zhang 	host = sdhci_pltfm_init(pdev, &sdhci_esdhc_imx_pdata,
1657070e6d3fSJisheng Zhang 				sizeof(*imx_data));
165885d6509dSShawn Guo 	if (IS_ERR(host))
165985d6509dSShawn Guo 		return PTR_ERR(host);
166085d6509dSShawn Guo 
166185d6509dSShawn Guo 	pltfm_host = sdhci_priv(host);
166285d6509dSShawn Guo 
1663070e6d3fSJisheng Zhang 	imx_data = sdhci_pltfm_priv(pltfm_host);
166457ed3314SShawn Guo 
166591b3d2e5SFabio Estevam 	imx_data->socdata = device_get_match_data(&pdev->dev);
166685d6509dSShawn Guo 
16671c4989b0SBOUGH CHEN 	if (imx_data->socdata->flags & ESDHC_FLAG_PMQOS)
1668d1b98305SRafael J. Wysocki 		cpu_latency_qos_add_request(&imx_data->pm_qos_req, 0);
16691c4989b0SBOUGH CHEN 
167052dac615SSascha Hauer 	imx_data->clk_ipg = devm_clk_get(&pdev->dev, "ipg");
167152dac615SSascha Hauer 	if (IS_ERR(imx_data->clk_ipg)) {
167252dac615SSascha Hauer 		err = PTR_ERR(imx_data->clk_ipg);
1673e3af31c6SShawn Guo 		goto free_sdhci;
167495f25efeSWolfram Sang 	}
167552dac615SSascha Hauer 
167652dac615SSascha Hauer 	imx_data->clk_ahb = devm_clk_get(&pdev->dev, "ahb");
167752dac615SSascha Hauer 	if (IS_ERR(imx_data->clk_ahb)) {
167852dac615SSascha Hauer 		err = PTR_ERR(imx_data->clk_ahb);
1679e3af31c6SShawn Guo 		goto free_sdhci;
168052dac615SSascha Hauer 	}
168152dac615SSascha Hauer 
168252dac615SSascha Hauer 	imx_data->clk_per = devm_clk_get(&pdev->dev, "per");
168352dac615SSascha Hauer 	if (IS_ERR(imx_data->clk_per)) {
168452dac615SSascha Hauer 		err = PTR_ERR(imx_data->clk_per);
1685e3af31c6SShawn Guo 		goto free_sdhci;
168652dac615SSascha Hauer 	}
168752dac615SSascha Hauer 
168852dac615SSascha Hauer 	pltfm_host->clk = imx_data->clk_per;
1689a974862fSDong Aisheng 	pltfm_host->clock = clk_get_rate(pltfm_host->clk);
169017b1eb7fSFabio Estevam 	err = clk_prepare_enable(imx_data->clk_per);
169117b1eb7fSFabio Estevam 	if (err)
169217b1eb7fSFabio Estevam 		goto free_sdhci;
169317b1eb7fSFabio Estevam 	err = clk_prepare_enable(imx_data->clk_ipg);
169417b1eb7fSFabio Estevam 	if (err)
169517b1eb7fSFabio Estevam 		goto disable_per_clk;
169617b1eb7fSFabio Estevam 	err = clk_prepare_enable(imx_data->clk_ahb);
169717b1eb7fSFabio Estevam 	if (err)
169817b1eb7fSFabio Estevam 		goto disable_ipg_clk;
169995f25efeSWolfram Sang 
1700ad93220dSDong Aisheng 	imx_data->pinctrl = devm_pinctrl_get(&pdev->dev);
17019e70ff99SHaibo Chen 	if (IS_ERR(imx_data->pinctrl))
1702b62eee9fSHaibo Chen 		dev_warn(mmc_dev(host->mmc), "could not get pinctrl\n");
1703e62d8b8fSDong Aisheng 
170469ed60e0SDong Aisheng 	if (esdhc_is_usdhc(imx_data)) {
170569ed60e0SDong Aisheng 		host->quirks2 |= SDHCI_QUIRK2_PRESET_VALUE_BROKEN;
170609c8192bSStefan Agner 		host->mmc->caps |= MMC_CAP_1_8V_DDR | MMC_CAP_3_3V_DDR;
1707f6140462SHaibo Chen 
1708f6140462SHaibo Chen 		/* GPIO CD can be set as a wakeup source */
1709f6140462SHaibo Chen 		host->mmc->caps |= MMC_CAP_CD_WAKE;
1710f6140462SHaibo Chen 
17114245afffSDong Aisheng 		if (!(imx_data->socdata->flags & ESDHC_FLAG_HS200))
17124245afffSDong Aisheng 			host->quirks2 |= SDHCI_QUIRK2_BROKEN_HS200;
1713a75dcbf4SDong Aisheng 
1714a75dcbf4SDong Aisheng 		/* clear tuning bits in case ROM has set it already */
1715a75dcbf4SDong Aisheng 		writel(0x0, host->ioaddr + ESDHC_MIX_CTRL);
1716869f8a69SAdrian Hunter 		writel(0x0, host->ioaddr + SDHCI_AUTO_CMD_STATUS);
1717a75dcbf4SDong Aisheng 		writel(0x0, host->ioaddr + ESDHC_TUNE_CTRL_STATUS);
1718de3e1dd0SBOUGH CHEN 
1719de3e1dd0SBOUGH CHEN 		/*
1720de3e1dd0SBOUGH CHEN 		 * Link usdhc specific mmc_host_ops execute_tuning function,
1721de3e1dd0SBOUGH CHEN 		 * to replace the standard one in sdhci_ops.
1722de3e1dd0SBOUGH CHEN 		 */
1723de3e1dd0SBOUGH CHEN 		host->mmc_host_ops.execute_tuning = usdhc_execute_tuning;
172452e4c32bSHaibo Chen 
172552e4c32bSHaibo Chen 		/*
172652e4c32bSHaibo Chen 		 * Link usdhc specific mmc_host_ops init card function,
172752e4c32bSHaibo Chen 		 * to distinguish the card type.
172852e4c32bSHaibo Chen 		 */
172952e4c32bSHaibo Chen 		host->mmc_host_ops.init_card = usdhc_init_card;
173069ed60e0SDong Aisheng 	}
1731f750ba9bSShawn Guo 
17326e9fd28eSDong Aisheng 	if (imx_data->socdata->flags & ESDHC_FLAG_MAN_TUNING)
17336e9fd28eSDong Aisheng 		sdhci_esdhc_ops.platform_execute_tuning =
17346e9fd28eSDong Aisheng 					esdhc_executing_tuning;
17358b2bb0adSDong Aisheng 
173618094430SDong Aisheng 	if (imx_data->socdata->flags & ESDHC_FLAG_ERR004536)
173718094430SDong Aisheng 		host->quirks |= SDHCI_QUIRK_BROKEN_ADMA;
173818094430SDong Aisheng 
173981dce149SHaibo Chen 	if (imx_data->socdata->flags & ESDHC_FLAG_HS400)
17402991ad76SLucas Stach 		host->mmc->caps2 |= MMC_CAP2_HS400;
174128b07674SHaibo Chen 
174274898cbcSHaibo Chen 	if (imx_data->socdata->flags & ESDHC_FLAG_BROKEN_AUTO_CMD23)
174374898cbcSHaibo Chen 		host->quirks2 |= SDHCI_QUIRK2_ACMD23_BROKEN;
174474898cbcSHaibo Chen 
174581dce149SHaibo Chen 	if (imx_data->socdata->flags & ESDHC_FLAG_HS400_ES) {
1746029e2476SBOUGH CHEN 		host->mmc->caps2 |= MMC_CAP2_HS400_ES;
1747029e2476SBOUGH CHEN 		host->mmc_host_ops.hs400_enhanced_strobe =
1748029e2476SBOUGH CHEN 					esdhc_hs400_enhanced_strobe;
1749029e2476SBOUGH CHEN 	}
1750029e2476SBOUGH CHEN 
1751bb6e3581SBOUGH CHEN 	if (imx_data->socdata->flags & ESDHC_FLAG_CQHCI) {
1752bcdb5301SBOUGH CHEN 		host->mmc->caps2 |= MMC_CAP2_CQE | MMC_CAP2_CQE_DCMD;
1753bb6e3581SBOUGH CHEN 		cq_host = devm_kzalloc(&pdev->dev, sizeof(*cq_host), GFP_KERNEL);
17549a633f3bSWei Yongjun 		if (!cq_host) {
17559a633f3bSWei Yongjun 			err = -ENOMEM;
1756bb6e3581SBOUGH CHEN 			goto disable_ahb_clk;
1757bb6e3581SBOUGH CHEN 		}
1758bb6e3581SBOUGH CHEN 
1759bb6e3581SBOUGH CHEN 		cq_host->mmio = host->ioaddr + ESDHC_CQHCI_ADDR_OFFSET;
1760bb6e3581SBOUGH CHEN 		cq_host->ops = &esdhc_cqhci_ops;
1761bb6e3581SBOUGH CHEN 
1762bb6e3581SBOUGH CHEN 		err = cqhci_init(cq_host, host->mmc, false);
1763bb6e3581SBOUGH CHEN 		if (err)
1764bb6e3581SBOUGH CHEN 			goto disable_ahb_clk;
1765bb6e3581SBOUGH CHEN 	}
1766bb6e3581SBOUGH CHEN 
176781dce149SHaibo Chen 	err = sdhci_esdhc_imx_probe_dt(pdev, host, imx_data);
176881dce149SHaibo Chen 	if (err)
176981dce149SHaibo Chen 		goto disable_ahb_clk;
177081dce149SHaibo Chen 
1771f3f5cf3dSDong Aisheng 	sdhci_esdhc_imx_hwinit(host);
1772f3f5cf3dSDong Aisheng 
177385d6509dSShawn Guo 	err = sdhci_add_host(host);
177485d6509dSShawn Guo 	if (err)
177517b1eb7fSFabio Estevam 		goto disable_ahb_clk;
177685d6509dSShawn Guo 
1777f62f7bccSHaibo Chen 	/*
1778f62f7bccSHaibo Chen 	 * Setup the wakeup capability here, let user to decide
1779f62f7bccSHaibo Chen 	 * whether need to enable this wakeup through sysfs interface.
1780f62f7bccSHaibo Chen 	 */
1781f62f7bccSHaibo Chen 	if ((host->mmc->pm_caps & MMC_PM_KEEP_POWER) &&
1782f62f7bccSHaibo Chen 			(host->mmc->pm_caps & MMC_PM_WAKE_SDIO_IRQ))
1783f62f7bccSHaibo Chen 		device_set_wakeup_capable(&pdev->dev, true);
1784f62f7bccSHaibo Chen 
178589d7e5c1SDong Aisheng 	pm_runtime_set_active(&pdev->dev);
178689d7e5c1SDong Aisheng 	pm_runtime_set_autosuspend_delay(&pdev->dev, 50);
178789d7e5c1SDong Aisheng 	pm_runtime_use_autosuspend(&pdev->dev);
178889d7e5c1SDong Aisheng 	pm_suspend_ignore_children(&pdev->dev, 1);
178977903c01SUlf Hansson 	pm_runtime_enable(&pdev->dev);
179089d7e5c1SDong Aisheng 
17917e29c306SWolfram Sang 	return 0;
17927e29c306SWolfram Sang 
179317b1eb7fSFabio Estevam disable_ahb_clk:
179452dac615SSascha Hauer 	clk_disable_unprepare(imx_data->clk_ahb);
179517b1eb7fSFabio Estevam disable_ipg_clk:
179617b1eb7fSFabio Estevam 	clk_disable_unprepare(imx_data->clk_ipg);
179717b1eb7fSFabio Estevam disable_per_clk:
179817b1eb7fSFabio Estevam 	clk_disable_unprepare(imx_data->clk_per);
1799e3af31c6SShawn Guo free_sdhci:
18001c4989b0SBOUGH CHEN 	if (imx_data->socdata->flags & ESDHC_FLAG_PMQOS)
1801d1b98305SRafael J. Wysocki 		cpu_latency_qos_remove_request(&imx_data->pm_qos_req);
180285d6509dSShawn Guo 	sdhci_pltfm_free(pdev);
180385d6509dSShawn Guo 	return err;
180495f25efeSWolfram Sang }
180595f25efeSWolfram Sang 
sdhci_esdhc_imx_remove(struct platform_device * pdev)180653b9222eSYangtao Li static void sdhci_esdhc_imx_remove(struct platform_device *pdev)
180795f25efeSWolfram Sang {
180885d6509dSShawn Guo 	struct sdhci_host *host = platform_get_drvdata(pdev);
180995f25efeSWolfram Sang 	struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
1810070e6d3fSJisheng Zhang 	struct pltfm_imx_data *imx_data = sdhci_pltfm_priv(pltfm_host);
1811a56f4413SFrank Li 	int dead;
181285d6509dSShawn Guo 
18130b414368SUlf Hansson 	pm_runtime_get_sync(&pdev->dev);
1814a56f4413SFrank Li 	dead = (readl(host->ioaddr + SDHCI_INT_STATUS) == 0xffffffff);
18150b414368SUlf Hansson 	pm_runtime_disable(&pdev->dev);
18160b414368SUlf Hansson 	pm_runtime_put_noidle(&pdev->dev);
18170b414368SUlf Hansson 
181885d6509dSShawn Guo 	sdhci_remove_host(host, dead);
18190c6d49ceSWolfram Sang 
182052dac615SSascha Hauer 	clk_disable_unprepare(imx_data->clk_per);
182152dac615SSascha Hauer 	clk_disable_unprepare(imx_data->clk_ipg);
182252dac615SSascha Hauer 	clk_disable_unprepare(imx_data->clk_ahb);
182352dac615SSascha Hauer 
18241c4989b0SBOUGH CHEN 	if (imx_data->socdata->flags & ESDHC_FLAG_PMQOS)
1825d1b98305SRafael J. Wysocki 		cpu_latency_qos_remove_request(&imx_data->pm_qos_req);
18261c4989b0SBOUGH CHEN 
182785d6509dSShawn Guo 	sdhci_pltfm_free(pdev);
182895f25efeSWolfram Sang }
182995f25efeSWolfram Sang 
18302788ed42SUlf Hansson #ifdef CONFIG_PM_SLEEP
sdhci_esdhc_suspend(struct device * dev)183104143fbaSDong Aisheng static int sdhci_esdhc_suspend(struct device *dev)
183204143fbaSDong Aisheng {
18333e3274abSUlf Hansson 	struct sdhci_host *host = dev_get_drvdata(dev);
1834a26a4f1bSHaibo Chen 	struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
1835a26a4f1bSHaibo Chen 	struct pltfm_imx_data *imx_data = sdhci_pltfm_priv(pltfm_host);
1836bb6e3581SBOUGH CHEN 	int ret;
1837bb6e3581SBOUGH CHEN 
1838bb6e3581SBOUGH CHEN 	if (host->mmc->caps2 & MMC_CAP2_CQE) {
1839bb6e3581SBOUGH CHEN 		ret = cqhci_suspend(host->mmc);
1840bb6e3581SBOUGH CHEN 		if (ret)
1841bb6e3581SBOUGH CHEN 			return ret;
1842bb6e3581SBOUGH CHEN 	}
18433e3274abSUlf Hansson 
1844a26a4f1bSHaibo Chen 	if ((imx_data->socdata->flags & ESDHC_FLAG_STATE_LOST_IN_LPMODE) &&
1845a26a4f1bSHaibo Chen 		(host->tuning_mode != SDHCI_TUNING_MODE_1)) {
1846a26a4f1bSHaibo Chen 		mmc_retune_timer_stop(host->mmc);
1847a26a4f1bSHaibo Chen 		mmc_retune_needed(host->mmc);
1848a26a4f1bSHaibo Chen 	}
1849a26a4f1bSHaibo Chen 
1850d38dcad4SAdrian Hunter 	if (host->tuning_mode != SDHCI_TUNING_MODE_3)
1851d38dcad4SAdrian Hunter 		mmc_retune_needed(host->mmc);
1852d38dcad4SAdrian Hunter 
1853af8fade4SHaibo Chen 	ret = sdhci_suspend_host(host);
1854f6140462SHaibo Chen 	if (ret)
1855f6140462SHaibo Chen 		return ret;
1856f6140462SHaibo Chen 
1857f6140462SHaibo Chen 	ret = pinctrl_pm_select_sleep_state(dev);
1858f6140462SHaibo Chen 	if (ret)
1859f6140462SHaibo Chen 		return ret;
1860f6140462SHaibo Chen 
1861f6140462SHaibo Chen 	ret = mmc_gpio_set_cd_wake(host->mmc, true);
1862af8fade4SHaibo Chen 
1863af8fade4SHaibo Chen 	return ret;
186404143fbaSDong Aisheng }
186504143fbaSDong Aisheng 
sdhci_esdhc_resume(struct device * dev)186604143fbaSDong Aisheng static int sdhci_esdhc_resume(struct device *dev)
186704143fbaSDong Aisheng {
1868cc17e129SDong Aisheng 	struct sdhci_host *host = dev_get_drvdata(dev);
1869bb6e3581SBOUGH CHEN 	int ret;
1870cc17e129SDong Aisheng 
1871af8fade4SHaibo Chen 	ret = pinctrl_pm_select_default_state(dev);
1872af8fade4SHaibo Chen 	if (ret)
1873af8fade4SHaibo Chen 		return ret;
1874af8fade4SHaibo Chen 
187519dbfdd3SDong Aisheng 	/* re-initialize hw state in case it's lost in low power mode */
187619dbfdd3SDong Aisheng 	sdhci_esdhc_imx_hwinit(host);
1877cc17e129SDong Aisheng 
1878bb6e3581SBOUGH CHEN 	ret = sdhci_resume_host(host);
1879bb6e3581SBOUGH CHEN 	if (ret)
1880bb6e3581SBOUGH CHEN 		return ret;
1881bb6e3581SBOUGH CHEN 
1882bb6e3581SBOUGH CHEN 	if (host->mmc->caps2 & MMC_CAP2_CQE)
1883bb6e3581SBOUGH CHEN 		ret = cqhci_resume(host->mmc);
1884bb6e3581SBOUGH CHEN 
1885f6140462SHaibo Chen 	if (!ret)
1886f6140462SHaibo Chen 		ret = mmc_gpio_set_cd_wake(host->mmc, false);
1887f6140462SHaibo Chen 
1888bb6e3581SBOUGH CHEN 	return ret;
188904143fbaSDong Aisheng }
18902788ed42SUlf Hansson #endif
189104143fbaSDong Aisheng 
18922788ed42SUlf Hansson #ifdef CONFIG_PM
sdhci_esdhc_runtime_suspend(struct device * dev)189389d7e5c1SDong Aisheng static int sdhci_esdhc_runtime_suspend(struct device *dev)
189489d7e5c1SDong Aisheng {
189589d7e5c1SDong Aisheng 	struct sdhci_host *host = dev_get_drvdata(dev);
189689d7e5c1SDong Aisheng 	struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
1897070e6d3fSJisheng Zhang 	struct pltfm_imx_data *imx_data = sdhci_pltfm_priv(pltfm_host);
189889d7e5c1SDong Aisheng 	int ret;
189989d7e5c1SDong Aisheng 
1900bb6e3581SBOUGH CHEN 	if (host->mmc->caps2 & MMC_CAP2_CQE) {
1901bb6e3581SBOUGH CHEN 		ret = cqhci_suspend(host->mmc);
1902bb6e3581SBOUGH CHEN 		if (ret)
1903bb6e3581SBOUGH CHEN 			return ret;
1904bb6e3581SBOUGH CHEN 	}
1905bb6e3581SBOUGH CHEN 
190689d7e5c1SDong Aisheng 	ret = sdhci_runtime_suspend_host(host);
1907371d39faSMichael Trimarchi 	if (ret)
1908371d39faSMichael Trimarchi 		return ret;
190989d7e5c1SDong Aisheng 
1910d38dcad4SAdrian Hunter 	if (host->tuning_mode != SDHCI_TUNING_MODE_3)
1911d38dcad4SAdrian Hunter 		mmc_retune_needed(host->mmc);
1912d38dcad4SAdrian Hunter 
19133602785bSMichael Trimarchi 	imx_data->actual_clock = host->mmc->actual_clock;
19143602785bSMichael Trimarchi 	esdhc_pltfm_set_clock(host, 0);
191589d7e5c1SDong Aisheng 	clk_disable_unprepare(imx_data->clk_per);
191689d7e5c1SDong Aisheng 	clk_disable_unprepare(imx_data->clk_ipg);
191789d7e5c1SDong Aisheng 	clk_disable_unprepare(imx_data->clk_ahb);
191889d7e5c1SDong Aisheng 
19191c4989b0SBOUGH CHEN 	if (imx_data->socdata->flags & ESDHC_FLAG_PMQOS)
1920d1b98305SRafael J. Wysocki 		cpu_latency_qos_remove_request(&imx_data->pm_qos_req);
19211c4989b0SBOUGH CHEN 
192289d7e5c1SDong Aisheng 	return ret;
192389d7e5c1SDong Aisheng }
192489d7e5c1SDong Aisheng 
sdhci_esdhc_runtime_resume(struct device * dev)192589d7e5c1SDong Aisheng static int sdhci_esdhc_runtime_resume(struct device *dev)
192689d7e5c1SDong Aisheng {
192789d7e5c1SDong Aisheng 	struct sdhci_host *host = dev_get_drvdata(dev);
192889d7e5c1SDong Aisheng 	struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
1929070e6d3fSJisheng Zhang 	struct pltfm_imx_data *imx_data = sdhci_pltfm_priv(pltfm_host);
193017b1eb7fSFabio Estevam 	int err;
193189d7e5c1SDong Aisheng 
19321c4989b0SBOUGH CHEN 	if (imx_data->socdata->flags & ESDHC_FLAG_PMQOS)
1933d1b98305SRafael J. Wysocki 		cpu_latency_qos_add_request(&imx_data->pm_qos_req, 0);
19341c4989b0SBOUGH CHEN 
19355c11f1ffSHaibo Chen 	if (imx_data->socdata->flags & ESDHC_FLAG_CLK_RATE_LOST_IN_PM_RUNTIME)
19365c11f1ffSHaibo Chen 		clk_set_rate(imx_data->clk_per, pltfm_host->clock);
19375c11f1ffSHaibo Chen 
1938a0ad3087SMichael Trimarchi 	err = clk_prepare_enable(imx_data->clk_ahb);
1939a0ad3087SMichael Trimarchi 	if (err)
19401c4989b0SBOUGH CHEN 		goto remove_pm_qos_request;
1941a0ad3087SMichael Trimarchi 
194217b1eb7fSFabio Estevam 	err = clk_prepare_enable(imx_data->clk_per);
194317b1eb7fSFabio Estevam 	if (err)
1944a0ad3087SMichael Trimarchi 		goto disable_ahb_clk;
1945af5d2b7bSUlf Hansson 
194617b1eb7fSFabio Estevam 	err = clk_prepare_enable(imx_data->clk_ipg);
194717b1eb7fSFabio Estevam 	if (err)
194817b1eb7fSFabio Estevam 		goto disable_per_clk;
1949af5d2b7bSUlf Hansson 
19503602785bSMichael Trimarchi 	esdhc_pltfm_set_clock(host, imx_data->actual_clock);
1951a0ad3087SMichael Trimarchi 
1952c6303c5dSBaolin Wang 	err = sdhci_runtime_resume_host(host, 0);
195317b1eb7fSFabio Estevam 	if (err)
1954a0ad3087SMichael Trimarchi 		goto disable_ipg_clk;
195589d7e5c1SDong Aisheng 
1956bb6e3581SBOUGH CHEN 	if (host->mmc->caps2 & MMC_CAP2_CQE)
1957bb6e3581SBOUGH CHEN 		err = cqhci_resume(host->mmc);
1958bb6e3581SBOUGH CHEN 
1959bb6e3581SBOUGH CHEN 	return err;
196017b1eb7fSFabio Estevam 
196117b1eb7fSFabio Estevam disable_ipg_clk:
196217b1eb7fSFabio Estevam 	clk_disable_unprepare(imx_data->clk_ipg);
196317b1eb7fSFabio Estevam disable_per_clk:
196417b1eb7fSFabio Estevam 	clk_disable_unprepare(imx_data->clk_per);
1965a0ad3087SMichael Trimarchi disable_ahb_clk:
1966a0ad3087SMichael Trimarchi 	clk_disable_unprepare(imx_data->clk_ahb);
19671c4989b0SBOUGH CHEN remove_pm_qos_request:
19681c4989b0SBOUGH CHEN 	if (imx_data->socdata->flags & ESDHC_FLAG_PMQOS)
1969d1b98305SRafael J. Wysocki 		cpu_latency_qos_remove_request(&imx_data->pm_qos_req);
197017b1eb7fSFabio Estevam 	return err;
197189d7e5c1SDong Aisheng }
197289d7e5c1SDong Aisheng #endif
197389d7e5c1SDong Aisheng 
197489d7e5c1SDong Aisheng static const struct dev_pm_ops sdhci_esdhc_pmops = {
197504143fbaSDong Aisheng 	SET_SYSTEM_SLEEP_PM_OPS(sdhci_esdhc_suspend, sdhci_esdhc_resume)
197689d7e5c1SDong Aisheng 	SET_RUNTIME_PM_OPS(sdhci_esdhc_runtime_suspend,
197789d7e5c1SDong Aisheng 				sdhci_esdhc_runtime_resume, NULL)
197889d7e5c1SDong Aisheng };
197989d7e5c1SDong Aisheng 
198085d6509dSShawn Guo static struct platform_driver sdhci_esdhc_imx_driver = {
198185d6509dSShawn Guo 	.driver		= {
198285d6509dSShawn Guo 		.name	= "sdhci-esdhc-imx",
198321b2cec6SDouglas Anderson 		.probe_type = PROBE_PREFER_ASYNCHRONOUS,
1984abfafc2dSShawn Guo 		.of_match_table = imx_esdhc_dt_ids,
198589d7e5c1SDong Aisheng 		.pm	= &sdhci_esdhc_pmops,
198685d6509dSShawn Guo 	},
198785d6509dSShawn Guo 	.probe		= sdhci_esdhc_imx_probe,
198853b9222eSYangtao Li 	.remove_new	= sdhci_esdhc_imx_remove,
198995f25efeSWolfram Sang };
199085d6509dSShawn Guo 
1991d1f81a64SAxel Lin module_platform_driver(sdhci_esdhc_imx_driver);
199285d6509dSShawn Guo 
199385d6509dSShawn Guo MODULE_DESCRIPTION("SDHCI driver for Freescale i.MX eSDHC");
1994035ff831SWolfram Sang MODULE_AUTHOR("Wolfram Sang <kernel@pengutronix.de>");
199585d6509dSShawn Guo MODULE_LICENSE("GPL v2");
1996