xref: /linux/drivers/mmc/host/sdhci-esdhc-imx.c (revision a1ff5a7d78a036d6c2178ee5acd6ba4946243800)
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
1745ae4b0d8SGiulio Benetti  * uSDHC: At 1.8V due to the I/O timing limit, for SDR mode, SD card
1755ae4b0d8SGiulio 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 
204a52b67bdSCiprian Costea /* The IP does not have GPIO CD wake capabilities */
205a52b67bdSCiprian Costea #define ESDHC_FLAG_SKIP_CD_WAKE		BIT(18)
206a52b67bdSCiprian Costea 
2074a11cc64SFabio Estevam enum wp_types {
2084a11cc64SFabio Estevam 	ESDHC_WP_NONE,		/* no WP, neither controller nor gpio */
2094a11cc64SFabio Estevam 	ESDHC_WP_CONTROLLER,	/* mmc controller internal WP */
2104a11cc64SFabio Estevam 	ESDHC_WP_GPIO,		/* external gpio pin for WP */
2114a11cc64SFabio Estevam };
2124a11cc64SFabio Estevam 
2134a11cc64SFabio Estevam enum cd_types {
2144a11cc64SFabio Estevam 	ESDHC_CD_NONE,		/* no CD, neither controller nor gpio */
2154a11cc64SFabio Estevam 	ESDHC_CD_CONTROLLER,	/* mmc controller internal CD */
2164a11cc64SFabio Estevam 	ESDHC_CD_GPIO,		/* external gpio pin for CD */
2174a11cc64SFabio Estevam 	ESDHC_CD_PERMANENT,	/* no CD, card permanently wired to host */
2184a11cc64SFabio Estevam };
2194a11cc64SFabio Estevam 
2204a11cc64SFabio Estevam /*
2214a11cc64SFabio Estevam  * struct esdhc_platform_data - platform data for esdhc on i.MX
2224a11cc64SFabio Estevam  *
2234a11cc64SFabio Estevam  * ESDHC_WP(CD)_CONTROLLER type is not available on i.MX25/35.
2244a11cc64SFabio Estevam  *
2254a11cc64SFabio Estevam  * @wp_type:	type of write_protect method (see wp_types enum above)
2264a11cc64SFabio Estevam  * @cd_type:	type of card_detect method (see cd_types enum above)
2274a11cc64SFabio Estevam  */
2284a11cc64SFabio Estevam 
2294a11cc64SFabio Estevam struct esdhc_platform_data {
2304a11cc64SFabio Estevam 	enum wp_types wp_type;
2314a11cc64SFabio Estevam 	enum cd_types cd_type;
2324a11cc64SFabio Estevam 	int max_bus_width;
2334a11cc64SFabio Estevam 	unsigned int delay_line;
2344a11cc64SFabio Estevam 	unsigned int tuning_step;       /* The delay cell steps in tuning procedure */
2354a11cc64SFabio Estevam 	unsigned int tuning_start_tap;	/* The start delay cell point in tuning procedure */
2364a11cc64SFabio Estevam 	unsigned int strobe_dll_delay_target;	/* The delay cell for strobe pad (read clock) */
2374a11cc64SFabio Estevam };
2384a11cc64SFabio Estevam 
239f47c4bbfSShawn Guo struct esdhc_soc_data {
240f47c4bbfSShawn Guo 	u32 flags;
241f47c4bbfSShawn Guo };
242f47c4bbfSShawn Guo 
2434f100012SAndrey Smirnov static const struct esdhc_soc_data esdhc_imx25_data = {
244667123f6SBenoît Thébaudeau 	.flags = ESDHC_FLAG_ERR004536,
245f47c4bbfSShawn Guo };
246f47c4bbfSShawn Guo 
2474f100012SAndrey Smirnov static const struct esdhc_soc_data esdhc_imx35_data = {
248667123f6SBenoît Thébaudeau 	.flags = ESDHC_FLAG_ERR004536,
249f47c4bbfSShawn Guo };
250f47c4bbfSShawn Guo 
2514f100012SAndrey Smirnov static const struct esdhc_soc_data esdhc_imx51_data = {
252f47c4bbfSShawn Guo 	.flags = 0,
253f47c4bbfSShawn Guo };
254f47c4bbfSShawn Guo 
2554f100012SAndrey Smirnov static const struct esdhc_soc_data esdhc_imx53_data = {
256f47c4bbfSShawn Guo 	.flags = ESDHC_FLAG_MULTIBLK_NO_INT,
257f47c4bbfSShawn Guo };
258f47c4bbfSShawn Guo 
2594f100012SAndrey Smirnov static const struct esdhc_soc_data usdhc_imx6q_data = {
26074898cbcSHaibo Chen 	.flags = ESDHC_FLAG_USDHC | ESDHC_FLAG_MAN_TUNING
26174898cbcSHaibo Chen 			| ESDHC_FLAG_BROKEN_AUTO_CMD23,
2626e9fd28eSDong Aisheng };
2636e9fd28eSDong Aisheng 
2644f100012SAndrey Smirnov static const struct esdhc_soc_data usdhc_imx6sl_data = {
2656e9fd28eSDong Aisheng 	.flags = ESDHC_FLAG_USDHC | ESDHC_FLAG_STD_TUNING
2664245afffSDong Aisheng 			| ESDHC_FLAG_HAVE_CAP1 | ESDHC_FLAG_ERR004536
26774898cbcSHaibo Chen 			| ESDHC_FLAG_HS200
26874898cbcSHaibo Chen 			| ESDHC_FLAG_BROKEN_AUTO_CMD23,
26974898cbcSHaibo Chen };
27074898cbcSHaibo Chen 
27174898cbcSHaibo Chen static const struct esdhc_soc_data usdhc_imx6sll_data = {
27274898cbcSHaibo Chen 	.flags = ESDHC_FLAG_USDHC | ESDHC_FLAG_STD_TUNING
27374898cbcSHaibo Chen 			| ESDHC_FLAG_HAVE_CAP1 | ESDHC_FLAG_HS200
27486b59671SHaibo Chen 			| ESDHC_FLAG_HS400
27574898cbcSHaibo Chen 			| ESDHC_FLAG_STATE_LOST_IN_LPMODE,
27657ed3314SShawn Guo };
27757ed3314SShawn Guo 
2784f100012SAndrey Smirnov static const struct esdhc_soc_data usdhc_imx6sx_data = {
279913d4951SDong Aisheng 	.flags = ESDHC_FLAG_USDHC | ESDHC_FLAG_STD_TUNING
280a26a4f1bSHaibo Chen 			| ESDHC_FLAG_HAVE_CAP1 | ESDHC_FLAG_HS200
28174898cbcSHaibo Chen 			| ESDHC_FLAG_STATE_LOST_IN_LPMODE
28274898cbcSHaibo Chen 			| ESDHC_FLAG_BROKEN_AUTO_CMD23,
283913d4951SDong Aisheng };
284913d4951SDong Aisheng 
285af6a50d4SBOUGH CHEN static const struct esdhc_soc_data usdhc_imx6ull_data = {
286af6a50d4SBOUGH CHEN 	.flags = ESDHC_FLAG_USDHC | ESDHC_FLAG_STD_TUNING
287af6a50d4SBOUGH CHEN 			| ESDHC_FLAG_HAVE_CAP1 | ESDHC_FLAG_HS200
288a26a4f1bSHaibo Chen 			| ESDHC_FLAG_ERR010450
289a26a4f1bSHaibo Chen 			| ESDHC_FLAG_STATE_LOST_IN_LPMODE,
290af6a50d4SBOUGH CHEN };
291af6a50d4SBOUGH CHEN 
2924f100012SAndrey Smirnov static const struct esdhc_soc_data usdhc_imx7d_data = {
29328b07674SHaibo Chen 	.flags = ESDHC_FLAG_USDHC | ESDHC_FLAG_STD_TUNING
29428b07674SHaibo Chen 			| ESDHC_FLAG_HAVE_CAP1 | ESDHC_FLAG_HS200
295a26a4f1bSHaibo Chen 			| ESDHC_FLAG_HS400
29674898cbcSHaibo Chen 			| ESDHC_FLAG_STATE_LOST_IN_LPMODE
29774898cbcSHaibo Chen 			| ESDHC_FLAG_BROKEN_AUTO_CMD23,
29828b07674SHaibo Chen };
29928b07674SHaibo Chen 
3005c4f0062SChester Lin static struct esdhc_soc_data usdhc_s32g2_data = {
3015c4f0062SChester Lin 	.flags = ESDHC_FLAG_USDHC | ESDHC_FLAG_MAN_TUNING
3025c4f0062SChester Lin 			| ESDHC_FLAG_HAVE_CAP1 | ESDHC_FLAG_HS200
3035c4f0062SChester Lin 			| ESDHC_FLAG_HS400 | ESDHC_FLAG_HS400_ES
304a52b67bdSCiprian Costea 			| ESDHC_FLAG_SKIP_ERR004536 | ESDHC_FLAG_SKIP_CD_WAKE,
3055c4f0062SChester Lin };
3065c4f0062SChester Lin 
3071c4989b0SBOUGH CHEN static struct esdhc_soc_data usdhc_imx7ulp_data = {
3081c4989b0SBOUGH CHEN 	.flags = ESDHC_FLAG_USDHC | ESDHC_FLAG_STD_TUNING
3091c4989b0SBOUGH CHEN 			| ESDHC_FLAG_HAVE_CAP1 | ESDHC_FLAG_HS200
310a26a4f1bSHaibo Chen 			| ESDHC_FLAG_PMQOS | ESDHC_FLAG_HS400
311a26a4f1bSHaibo Chen 			| ESDHC_FLAG_STATE_LOST_IN_LPMODE,
3121c4989b0SBOUGH CHEN };
3132f4788f3SJesse Taube static struct esdhc_soc_data usdhc_imxrt1050_data = {
314d7a1830eSGiulio Benetti 	.flags = ESDHC_FLAG_USDHC | ESDHC_FLAG_STD_TUNING
315d7a1830eSGiulio Benetti 			| ESDHC_FLAG_HAVE_CAP1 | ESDHC_FLAG_HS200,
3162f4788f3SJesse Taube };
3171c4989b0SBOUGH CHEN 
318029e2476SBOUGH CHEN static struct esdhc_soc_data usdhc_imx8qxp_data = {
319029e2476SBOUGH CHEN 	.flags = ESDHC_FLAG_USDHC | ESDHC_FLAG_STD_TUNING
320029e2476SBOUGH CHEN 			| ESDHC_FLAG_HAVE_CAP1 | ESDHC_FLAG_HS200
321bb6e3581SBOUGH CHEN 			| ESDHC_FLAG_HS400 | ESDHC_FLAG_HS400_ES
3225c11f1ffSHaibo Chen 			| ESDHC_FLAG_STATE_LOST_IN_LPMODE
3235c11f1ffSHaibo Chen 			| ESDHC_FLAG_CLK_RATE_LOST_IN_PM_RUNTIME,
324029e2476SBOUGH CHEN };
325029e2476SBOUGH CHEN 
326cde5e8e9SHaibo Chen static struct esdhc_soc_data usdhc_imx8mm_data = {
327cde5e8e9SHaibo Chen 	.flags = ESDHC_FLAG_USDHC | ESDHC_FLAG_STD_TUNING
328cde5e8e9SHaibo Chen 			| ESDHC_FLAG_HAVE_CAP1 | ESDHC_FLAG_HS200
329cde5e8e9SHaibo Chen 			| ESDHC_FLAG_HS400 | ESDHC_FLAG_HS400_ES
330cde5e8e9SHaibo Chen 			| ESDHC_FLAG_STATE_LOST_IN_LPMODE,
331e149860dSRichard Zhu };
332e149860dSRichard Zhu 
333e149860dSRichard Zhu struct pltfm_imx_data {
334e149860dSRichard Zhu 	u32 scratchpad;
335e62d8b8fSDong Aisheng 	struct pinctrl *pinctrl;
336ad93220dSDong Aisheng 	struct pinctrl_state *pins_100mhz;
337ad93220dSDong Aisheng 	struct pinctrl_state *pins_200mhz;
338f47c4bbfSShawn Guo 	const struct esdhc_soc_data *socdata;
339842afc02SShawn Guo 	struct esdhc_platform_data boarddata;
34052dac615SSascha Hauer 	struct clk *clk_ipg;
34152dac615SSascha Hauer 	struct clk *clk_ahb;
34252dac615SSascha Hauer 	struct clk *clk_per;
3433602785bSMichael Trimarchi 	unsigned int actual_clock;
34452e4c32bSHaibo Chen 
34552e4c32bSHaibo Chen 	/*
34652e4c32bSHaibo Chen 	 * USDHC has one limition, require the SDIO device a different
34752e4c32bSHaibo Chen 	 * register setting. Driver has to recognize card type during
34852e4c32bSHaibo Chen 	 * the card init, but at this stage, mmc_host->card is not
34952e4c32bSHaibo Chen 	 * available. So involve this field to save the card type
35052e4c32bSHaibo Chen 	 * during card init through usdhc_init_card().
35152e4c32bSHaibo Chen 	 */
35252e4c32bSHaibo Chen 	unsigned int init_card_type;
35352e4c32bSHaibo Chen 
354361b8482SLucas Stach 	enum {
355361b8482SLucas Stach 		NO_CMD_PENDING,      /* no multiblock command pending */
356361b8482SLucas Stach 		MULTIBLK_IN_PROCESS, /* exact multiblock cmd in process */
357361b8482SLucas Stach 		WAIT_FOR_INT,        /* sent CMD12, waiting for response INT */
358361b8482SLucas Stach 	} multiblock_status;
359de5bdbffSDong Aisheng 	u32 is_ddr;
3601c4989b0SBOUGH CHEN 	struct pm_qos_request pm_qos_req;
361e149860dSRichard Zhu };
362e149860dSRichard Zhu 
363abfafc2dSShawn Guo static const struct of_device_id imx_esdhc_dt_ids[] = {
364f47c4bbfSShawn Guo 	{ .compatible = "fsl,imx25-esdhc", .data = &esdhc_imx25_data, },
365f47c4bbfSShawn Guo 	{ .compatible = "fsl,imx35-esdhc", .data = &esdhc_imx35_data, },
366f47c4bbfSShawn Guo 	{ .compatible = "fsl,imx51-esdhc", .data = &esdhc_imx51_data, },
367f47c4bbfSShawn Guo 	{ .compatible = "fsl,imx53-esdhc", .data = &esdhc_imx53_data, },
368913d4951SDong Aisheng 	{ .compatible = "fsl,imx6sx-usdhc", .data = &usdhc_imx6sx_data, },
3696e9fd28eSDong Aisheng 	{ .compatible = "fsl,imx6sl-usdhc", .data = &usdhc_imx6sl_data, },
37074898cbcSHaibo Chen 	{ .compatible = "fsl,imx6sll-usdhc", .data = &usdhc_imx6sll_data, },
371f47c4bbfSShawn Guo 	{ .compatible = "fsl,imx6q-usdhc", .data = &usdhc_imx6q_data, },
372af6a50d4SBOUGH CHEN 	{ .compatible = "fsl,imx6ull-usdhc", .data = &usdhc_imx6ull_data, },
37328b07674SHaibo Chen 	{ .compatible = "fsl,imx7d-usdhc", .data = &usdhc_imx7d_data, },
3741c4989b0SBOUGH CHEN 	{ .compatible = "fsl,imx7ulp-usdhc", .data = &usdhc_imx7ulp_data, },
375029e2476SBOUGH CHEN 	{ .compatible = "fsl,imx8qxp-usdhc", .data = &usdhc_imx8qxp_data, },
376cde5e8e9SHaibo Chen 	{ .compatible = "fsl,imx8mm-usdhc", .data = &usdhc_imx8mm_data, },
3772f4788f3SJesse Taube 	{ .compatible = "fsl,imxrt1050-usdhc", .data = &usdhc_imxrt1050_data, },
3785c4f0062SChester Lin 	{ .compatible = "nxp,s32g2-usdhc", .data = &usdhc_s32g2_data, },
379abfafc2dSShawn Guo 	{ /* sentinel */ }
380abfafc2dSShawn Guo };
381abfafc2dSShawn Guo MODULE_DEVICE_TABLE(of, imx_esdhc_dt_ids);
382abfafc2dSShawn Guo 
is_imx25_esdhc(struct pltfm_imx_data * data)38357ed3314SShawn Guo static inline int is_imx25_esdhc(struct pltfm_imx_data *data)
38457ed3314SShawn Guo {
385f47c4bbfSShawn Guo 	return data->socdata == &esdhc_imx25_data;
38657ed3314SShawn Guo }
38757ed3314SShawn Guo 
is_imx53_esdhc(struct pltfm_imx_data * data)38857ed3314SShawn Guo static inline int is_imx53_esdhc(struct pltfm_imx_data *data)
38957ed3314SShawn Guo {
390f47c4bbfSShawn Guo 	return data->socdata == &esdhc_imx53_data;
39157ed3314SShawn Guo }
39257ed3314SShawn Guo 
esdhc_is_usdhc(struct pltfm_imx_data * data)3939d61c009SShawn Guo static inline int esdhc_is_usdhc(struct pltfm_imx_data *data)
3949d61c009SShawn Guo {
395f47c4bbfSShawn Guo 	return !!(data->socdata->flags & ESDHC_FLAG_USDHC);
3969d61c009SShawn Guo }
3979d61c009SShawn Guo 
esdhc_clrset_le(struct sdhci_host * host,u32 mask,u32 val,int reg)39895f25efeSWolfram Sang static inline void esdhc_clrset_le(struct sdhci_host *host, u32 mask, u32 val, int reg)
39995f25efeSWolfram Sang {
40095f25efeSWolfram Sang 	void __iomem *base = host->ioaddr + (reg & ~0x3);
40195f25efeSWolfram Sang 	u32 shift = (reg & 0x3) * 8;
40295f25efeSWolfram Sang 
40395f25efeSWolfram Sang 	writel(((readl(base) & ~(mask << shift)) | (val << shift)), base);
40495f25efeSWolfram Sang }
40595f25efeSWolfram Sang 
4063722c74cSHaibo Chen #define DRIVER_NAME "sdhci-esdhc-imx"
4073722c74cSHaibo Chen #define ESDHC_IMX_DUMP(f, x...) \
4083722c74cSHaibo Chen 	pr_err("%s: " DRIVER_NAME ": " f, mmc_hostname(host->mmc), ## x)
esdhc_dump_debug_regs(struct sdhci_host * host)4093722c74cSHaibo Chen static void esdhc_dump_debug_regs(struct sdhci_host *host)
4103722c74cSHaibo Chen {
4113722c74cSHaibo Chen 	int i;
4123722c74cSHaibo Chen 	char *debug_status[7] = {
4133722c74cSHaibo Chen 				 "cmd debug status",
4143722c74cSHaibo Chen 				 "data debug status",
4153722c74cSHaibo Chen 				 "trans debug status",
4163722c74cSHaibo Chen 				 "dma debug status",
4173722c74cSHaibo Chen 				 "adma debug status",
4183722c74cSHaibo Chen 				 "fifo debug status",
4193722c74cSHaibo Chen 				 "async fifo debug status"
4203722c74cSHaibo Chen 	};
4213722c74cSHaibo Chen 
4223722c74cSHaibo Chen 	ESDHC_IMX_DUMP("========= ESDHC IMX DEBUG STATUS DUMP =========\n");
4233722c74cSHaibo Chen 	for (i = 0; i < 7; i++) {
4243722c74cSHaibo Chen 		esdhc_clrset_le(host, ESDHC_DEBUG_SEL_MASK,
4253722c74cSHaibo Chen 			ESDHC_DEBUG_SEL_CMD_STATE + i, ESDHC_DEBUG_SEL_REG);
4263722c74cSHaibo Chen 		ESDHC_IMX_DUMP("%s:  0x%04x\n", debug_status[i],
4273722c74cSHaibo Chen 			readw(host->ioaddr + ESDHC_DEBUG_SEL_AND_STATUS_REG));
4283722c74cSHaibo Chen 	}
4293722c74cSHaibo Chen 
4303722c74cSHaibo Chen 	esdhc_clrset_le(host, ESDHC_DEBUG_SEL_MASK, 0, ESDHC_DEBUG_SEL_REG);
4313722c74cSHaibo Chen 
4323722c74cSHaibo Chen }
4333722c74cSHaibo Chen 
esdhc_wait_for_card_clock_gate_off(struct sdhci_host * host)434f581e909SHaibo Chen static inline void esdhc_wait_for_card_clock_gate_off(struct sdhci_host *host)
435f581e909SHaibo Chen {
436f581e909SHaibo Chen 	u32 present_state;
437f581e909SHaibo Chen 	int ret;
438f581e909SHaibo Chen 
439f581e909SHaibo Chen 	ret = readl_poll_timeout(host->ioaddr + ESDHC_PRSSTAT, present_state,
440f581e909SHaibo Chen 				(present_state & ESDHC_CLOCK_GATE_OFF), 2, 100);
441f581e909SHaibo Chen 	if (ret == -ETIMEDOUT)
442f581e909SHaibo Chen 		dev_warn(mmc_dev(host->mmc), "%s: card clock still not gate off in 100us!.\n", __func__);
443f581e909SHaibo Chen }
444f581e909SHaibo Chen 
44545334ee1SHaibo 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)446c8c49a5aSHaibo Chen static inline void usdhc_auto_tuning_mode_sel_and_en(struct sdhci_host *host)
44745334ee1SHaibo Chen {
44852e4c32bSHaibo Chen 	struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
44952e4c32bSHaibo Chen 	struct pltfm_imx_data *imx_data = sdhci_pltfm_priv(pltfm_host);
45045334ee1SHaibo Chen 	u32 buswidth, auto_tune_buswidth;
451c8c49a5aSHaibo Chen 	u32 reg;
45245334ee1SHaibo Chen 
45345334ee1SHaibo Chen 	buswidth = USDHC_GET_BUSWIDTH(readl(host->ioaddr + SDHCI_HOST_CONTROL));
45445334ee1SHaibo Chen 
45545334ee1SHaibo Chen 	switch (buswidth) {
45645334ee1SHaibo Chen 	case ESDHC_CTRL_8BITBUS:
45745334ee1SHaibo Chen 		auto_tune_buswidth = ESDHC_VEND_SPEC2_AUTO_TUNE_8BIT_EN;
45845334ee1SHaibo Chen 		break;
45945334ee1SHaibo Chen 	case ESDHC_CTRL_4BITBUS:
46045334ee1SHaibo Chen 		auto_tune_buswidth = ESDHC_VEND_SPEC2_AUTO_TUNE_4BIT_EN;
46145334ee1SHaibo Chen 		break;
46245334ee1SHaibo Chen 	default:	/* 1BITBUS */
46345334ee1SHaibo Chen 		auto_tune_buswidth = ESDHC_VEND_SPEC2_AUTO_TUNE_1BIT_EN;
46445334ee1SHaibo Chen 		break;
46545334ee1SHaibo Chen 	}
46645334ee1SHaibo Chen 
46752e4c32bSHaibo Chen 	/*
46852e4c32bSHaibo Chen 	 * For USDHC, auto tuning circuit can not handle the async sdio
46952e4c32bSHaibo Chen 	 * device interrupt correctly. When sdio device use 4 data lines,
47052e4c32bSHaibo Chen 	 * async sdio interrupt will use the shared DAT[1], if enable auto
47152e4c32bSHaibo Chen 	 * tuning circuit check these 4 data lines, include the DAT[1],
47252e4c32bSHaibo Chen 	 * this circuit will detect this interrupt, take this as a data on
47352e4c32bSHaibo Chen 	 * DAT[1], and adjust the delay cell wrongly.
47452e4c32bSHaibo Chen 	 * This is the hardware design limitation, to avoid this, for sdio
47552e4c32bSHaibo Chen 	 * device, config the auto tuning circuit only check DAT[0] and CMD
47652e4c32bSHaibo Chen 	 * line.
47752e4c32bSHaibo Chen 	 */
47852e4c32bSHaibo Chen 	if (imx_data->init_card_type == MMC_TYPE_SDIO)
47952e4c32bSHaibo Chen 		auto_tune_buswidth = ESDHC_VEND_SPEC2_AUTO_TUNE_1BIT_EN;
48052e4c32bSHaibo Chen 
48145334ee1SHaibo Chen 	esdhc_clrset_le(host, ESDHC_VEND_SPEC2_AUTO_TUNE_MODE_MASK,
48245334ee1SHaibo Chen 			auto_tune_buswidth | ESDHC_VEND_SPEC2_AUTO_TUNE_CMD_EN,
48345334ee1SHaibo Chen 			ESDHC_VEND_SPEC2);
484c8c49a5aSHaibo Chen 
485c8c49a5aSHaibo Chen 	reg = readl(host->ioaddr + ESDHC_MIX_CTRL);
486c8c49a5aSHaibo Chen 	reg |= ESDHC_MIX_CTRL_AUTO_TUNE_EN;
487c8c49a5aSHaibo Chen 	writel(reg, host->ioaddr + ESDHC_MIX_CTRL);
48845334ee1SHaibo Chen }
48945334ee1SHaibo Chen 
esdhc_readl_le(struct sdhci_host * host,int reg)4907e29c306SWolfram Sang static u32 esdhc_readl_le(struct sdhci_host *host, int reg)
4917e29c306SWolfram Sang {
492361b8482SLucas Stach 	struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
493070e6d3fSJisheng Zhang 	struct pltfm_imx_data *imx_data = sdhci_pltfm_priv(pltfm_host);
494913413c3SShawn Guo 	u32 val = readl(host->ioaddr + reg);
495913413c3SShawn Guo 
4960322191eSDong Aisheng 	if (unlikely(reg == SDHCI_PRESENT_STATE)) {
4970322191eSDong Aisheng 		u32 fsl_prss = val;
4980322191eSDong Aisheng 		/* save the least 20 bits */
4990322191eSDong Aisheng 		val = fsl_prss & 0x000FFFFF;
5000322191eSDong Aisheng 		/* move dat[0-3] bits */
5010322191eSDong Aisheng 		val |= (fsl_prss & 0x0F000000) >> 4;
5020322191eSDong Aisheng 		/* move cmd line bit */
5030322191eSDong Aisheng 		val |= (fsl_prss & 0x00800000) << 1;
5040322191eSDong Aisheng 	}
5050322191eSDong Aisheng 
50697e4ba6aSRichard Zhu 	if (unlikely(reg == SDHCI_CAPABILITIES)) {
5076b4fb671SDong Aisheng 		/* ignore bit[0-15] as it stores cap_1 register val for mx6sl */
5086b4fb671SDong Aisheng 		if (imx_data->socdata->flags & ESDHC_FLAG_HAVE_CAP1)
5096b4fb671SDong Aisheng 			val &= 0xffff0000;
5106b4fb671SDong Aisheng 
51197e4ba6aSRichard Zhu 		/* In FSL esdhc IC module, only bit20 is used to indicate the
51297e4ba6aSRichard Zhu 		 * ADMA2 capability of esdhc, but this bit is messed up on
51397e4ba6aSRichard Zhu 		 * some SOCs (e.g. on MX25, MX35 this bit is set, but they
51497e4ba6aSRichard Zhu 		 * don't actually support ADMA2). So set the BROKEN_ADMA
515d04f8d5bSBenoît Thébaudeau 		 * quirk on MX25/35 platforms.
51697e4ba6aSRichard Zhu 		 */
51797e4ba6aSRichard Zhu 
51897e4ba6aSRichard Zhu 		if (val & SDHCI_CAN_DO_ADMA1) {
51997e4ba6aSRichard Zhu 			val &= ~SDHCI_CAN_DO_ADMA1;
52097e4ba6aSRichard Zhu 			val |= SDHCI_CAN_DO_ADMA2;
52197e4ba6aSRichard Zhu 		}
52297e4ba6aSRichard Zhu 	}
52397e4ba6aSRichard Zhu 
5246e9fd28eSDong Aisheng 	if (unlikely(reg == SDHCI_CAPABILITIES_1)) {
5256e9fd28eSDong Aisheng 		if (esdhc_is_usdhc(imx_data)) {
5266e9fd28eSDong Aisheng 			if (imx_data->socdata->flags & ESDHC_FLAG_HAVE_CAP1)
5276e9fd28eSDong Aisheng 				val = readl(host->ioaddr + SDHCI_CAPABILITIES) & 0xFFFF;
5286e9fd28eSDong Aisheng 			else
5296e9fd28eSDong Aisheng 				/* imx6q/dl does not have cap_1 register, fake one */
5300322191eSDong Aisheng 				val = SDHCI_SUPPORT_DDR50 | SDHCI_SUPPORT_SDR104
531888824bbSDong Aisheng 					| SDHCI_SUPPORT_SDR50
532da0295ffSDong Aisheng 					| SDHCI_USE_SDR50_TUNING
533a8e809ecSMasahiro Yamada 					| FIELD_PREP(SDHCI_RETUNING_MODE_MASK,
534a8e809ecSMasahiro Yamada 						     SDHCI_TUNING_MODE_3);
53528b07674SHaibo Chen 
53692748beaSStefan Agner 			/*
53792748beaSStefan Agner 			 * Do not advertise faster UHS modes if there are no
53892748beaSStefan Agner 			 * pinctrl states for 100MHz/200MHz.
53992748beaSStefan Agner 			 */
54025e8b9ebSShawn Guo 			if (IS_ERR_OR_NULL(imx_data->pins_100mhz))
54125e8b9ebSShawn Guo 				val &= ~(SDHCI_SUPPORT_SDR50 | SDHCI_SUPPORT_DDR50);
54225e8b9ebSShawn Guo 			if (IS_ERR_OR_NULL(imx_data->pins_200mhz))
54325e8b9ebSShawn Guo 				val &= ~(SDHCI_SUPPORT_SDR104 | SDHCI_SUPPORT_HS400);
5446e9fd28eSDong Aisheng 		}
5456e9fd28eSDong Aisheng 	}
5460322191eSDong Aisheng 
5479d61c009SShawn Guo 	if (unlikely(reg == SDHCI_MAX_CURRENT) && esdhc_is_usdhc(imx_data)) {
5480322191eSDong Aisheng 		val = 0;
549804a65b3SMasahiro Yamada 		val |= FIELD_PREP(SDHCI_MAX_CURRENT_330_MASK, 0xFF);
550804a65b3SMasahiro Yamada 		val |= FIELD_PREP(SDHCI_MAX_CURRENT_300_MASK, 0xFF);
551804a65b3SMasahiro Yamada 		val |= FIELD_PREP(SDHCI_MAX_CURRENT_180_MASK, 0xFF);
5520322191eSDong Aisheng 	}
5530322191eSDong Aisheng 
55497e4ba6aSRichard Zhu 	if (unlikely(reg == SDHCI_INT_STATUS)) {
55560bf6396SShawn Guo 		if (val & ESDHC_INT_VENDOR_SPEC_DMA_ERR) {
55660bf6396SShawn Guo 			val &= ~ESDHC_INT_VENDOR_SPEC_DMA_ERR;
55797e4ba6aSRichard Zhu 			val |= SDHCI_INT_ADMA_ERROR;
55897e4ba6aSRichard Zhu 		}
559361b8482SLucas Stach 
560361b8482SLucas Stach 		/*
561361b8482SLucas Stach 		 * mask off the interrupt we get in response to the manually
562361b8482SLucas Stach 		 * sent CMD12
563361b8482SLucas Stach 		 */
564361b8482SLucas Stach 		if ((imx_data->multiblock_status == WAIT_FOR_INT) &&
565361b8482SLucas Stach 		    ((val & SDHCI_INT_RESPONSE) == SDHCI_INT_RESPONSE)) {
566361b8482SLucas Stach 			val &= ~SDHCI_INT_RESPONSE;
567361b8482SLucas Stach 			writel(SDHCI_INT_RESPONSE, host->ioaddr +
568361b8482SLucas Stach 						   SDHCI_INT_STATUS);
569361b8482SLucas Stach 			imx_data->multiblock_status = NO_CMD_PENDING;
570361b8482SLucas Stach 		}
57197e4ba6aSRichard Zhu 	}
57297e4ba6aSRichard Zhu 
5737e29c306SWolfram Sang 	return val;
5747e29c306SWolfram Sang }
5757e29c306SWolfram Sang 
esdhc_writel_le(struct sdhci_host * host,u32 val,int reg)5767e29c306SWolfram Sang static void esdhc_writel_le(struct sdhci_host *host, u32 val, int reg)
5777e29c306SWolfram Sang {
578e149860dSRichard Zhu 	struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
579070e6d3fSJisheng Zhang 	struct pltfm_imx_data *imx_data = sdhci_pltfm_priv(pltfm_host);
5800d58864bSTony Lin 	u32 data;
581e149860dSRichard Zhu 
58277da3da0SAaron Brice 	if (unlikely(reg == SDHCI_INT_ENABLE || reg == SDHCI_SIGNAL_ENABLE ||
58377da3da0SAaron Brice 			reg == SDHCI_INT_STATUS)) {
584b7321042SDong Aisheng 		if ((val & SDHCI_INT_CARD_INT) && !esdhc_is_usdhc(imx_data)) {
5850d58864bSTony Lin 			/*
5860d58864bSTony Lin 			 * Clear and then set D3CD bit to avoid missing the
587d04f8d5bSBenoît Thébaudeau 			 * card interrupt. This is an eSDHC controller problem
5880d58864bSTony Lin 			 * so we need to apply the following workaround: clear
5890d58864bSTony Lin 			 * and set D3CD bit will make eSDHC re-sample the card
5900d58864bSTony Lin 			 * interrupt. In case a card interrupt was lost,
5910d58864bSTony Lin 			 * re-sample it by the following steps.
5920d58864bSTony Lin 			 */
5930d58864bSTony Lin 			data = readl(host->ioaddr + SDHCI_HOST_CONTROL);
59460bf6396SShawn Guo 			data &= ~ESDHC_CTRL_D3CD;
5950d58864bSTony Lin 			writel(data, host->ioaddr + SDHCI_HOST_CONTROL);
59660bf6396SShawn Guo 			data |= ESDHC_CTRL_D3CD;
5970d58864bSTony Lin 			writel(data, host->ioaddr + SDHCI_HOST_CONTROL);
5980d58864bSTony Lin 		}
599915be485SDong Aisheng 
600915be485SDong Aisheng 		if (val & SDHCI_INT_ADMA_ERROR) {
601915be485SDong Aisheng 			val &= ~SDHCI_INT_ADMA_ERROR;
602915be485SDong Aisheng 			val |= ESDHC_INT_VENDOR_SPEC_DMA_ERR;
603915be485SDong Aisheng 		}
6040d58864bSTony Lin 	}
6050d58864bSTony Lin 
606f47c4bbfSShawn Guo 	if (unlikely((imx_data->socdata->flags & ESDHC_FLAG_MULTIBLK_NO_INT)
60758ac8177SRichard Zhu 				&& (reg == SDHCI_INT_STATUS)
60858ac8177SRichard Zhu 				&& (val & SDHCI_INT_DATA_END))) {
60958ac8177SRichard Zhu 			u32 v;
61060bf6396SShawn Guo 			v = readl(host->ioaddr + ESDHC_VENDOR_SPEC);
61160bf6396SShawn Guo 			v &= ~ESDHC_VENDOR_SPEC_SDIO_QUIRK;
61260bf6396SShawn Guo 			writel(v, host->ioaddr + ESDHC_VENDOR_SPEC);
613361b8482SLucas Stach 
614361b8482SLucas Stach 			if (imx_data->multiblock_status == MULTIBLK_IN_PROCESS)
615361b8482SLucas Stach 			{
616361b8482SLucas Stach 				/* send a manual CMD12 with RESPTYP=none */
617361b8482SLucas Stach 				data = MMC_STOP_TRANSMISSION << 24 |
618361b8482SLucas Stach 				       SDHCI_CMD_ABORTCMD << 16;
619361b8482SLucas Stach 				writel(data, host->ioaddr + SDHCI_TRANSFER_MODE);
620361b8482SLucas Stach 				imx_data->multiblock_status = WAIT_FOR_INT;
621361b8482SLucas Stach 			}
62258ac8177SRichard Zhu 	}
62358ac8177SRichard Zhu 
6247e29c306SWolfram Sang 	writel(val, host->ioaddr + reg);
6257e29c306SWolfram Sang }
6267e29c306SWolfram Sang 
esdhc_readw_le(struct sdhci_host * host,int reg)62795f25efeSWolfram Sang static u16 esdhc_readw_le(struct sdhci_host *host, int reg)
62895f25efeSWolfram Sang {
629ef4d0888SShawn Guo 	struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
630070e6d3fSJisheng Zhang 	struct pltfm_imx_data *imx_data = sdhci_pltfm_priv(pltfm_host);
6310322191eSDong Aisheng 	u16 ret = 0;
6320322191eSDong Aisheng 	u32 val;
633ef4d0888SShawn Guo 
63495a2482aSShawn Guo 	if (unlikely(reg == SDHCI_HOST_VERSION)) {
635ef4d0888SShawn Guo 		reg ^= 2;
6369d61c009SShawn Guo 		if (esdhc_is_usdhc(imx_data)) {
63795a2482aSShawn Guo 			/*
638ef4d0888SShawn Guo 			 * The usdhc register returns a wrong host version.
639ef4d0888SShawn Guo 			 * Correct it here.
64095a2482aSShawn Guo 			 */
641ef4d0888SShawn Guo 			return SDHCI_SPEC_300;
642ef4d0888SShawn Guo 		}
64395a2482aSShawn Guo 	}
64495f25efeSWolfram Sang 
6450322191eSDong Aisheng 	if (unlikely(reg == SDHCI_HOST_CONTROL2)) {
6460322191eSDong Aisheng 		val = readl(host->ioaddr + ESDHC_VENDOR_SPEC);
6470322191eSDong Aisheng 		if (val & ESDHC_VENDOR_SPEC_VSELECT)
6480322191eSDong Aisheng 			ret |= SDHCI_CTRL_VDD_180;
6490322191eSDong Aisheng 
6509d61c009SShawn Guo 		if (esdhc_is_usdhc(imx_data)) {
6516e9fd28eSDong Aisheng 			if (imx_data->socdata->flags & ESDHC_FLAG_MAN_TUNING)
6520322191eSDong Aisheng 				val = readl(host->ioaddr + ESDHC_MIX_CTRL);
6536e9fd28eSDong Aisheng 			else if (imx_data->socdata->flags & ESDHC_FLAG_STD_TUNING)
6546e9fd28eSDong Aisheng 				/* the std tuning bits is in ACMD12_ERR for imx6sl */
655869f8a69SAdrian Hunter 				val = readl(host->ioaddr + SDHCI_AUTO_CMD_STATUS);
6566e9fd28eSDong Aisheng 		}
6576e9fd28eSDong Aisheng 
6580322191eSDong Aisheng 		if (val & ESDHC_MIX_CTRL_EXE_TUNE)
6590322191eSDong Aisheng 			ret |= SDHCI_CTRL_EXEC_TUNING;
6600322191eSDong Aisheng 		if (val & ESDHC_MIX_CTRL_SMPCLK_SEL)
6610322191eSDong Aisheng 			ret |= SDHCI_CTRL_TUNED_CLK;
6620322191eSDong Aisheng 
6630322191eSDong Aisheng 		ret &= ~SDHCI_CTRL_PRESET_VAL_ENABLE;
6640322191eSDong Aisheng 
6650322191eSDong Aisheng 		return ret;
6660322191eSDong Aisheng 	}
6670322191eSDong Aisheng 
6687dd109efSDong Aisheng 	if (unlikely(reg == SDHCI_TRANSFER_MODE)) {
6697dd109efSDong Aisheng 		if (esdhc_is_usdhc(imx_data)) {
6707dd109efSDong Aisheng 			u32 m = readl(host->ioaddr + ESDHC_MIX_CTRL);
6717dd109efSDong Aisheng 			ret = m & ESDHC_MIX_CTRL_SDHCI_MASK;
6727dd109efSDong Aisheng 			/* Swap AC23 bit */
6737dd109efSDong Aisheng 			if (m & ESDHC_MIX_CTRL_AC23EN) {
6747dd109efSDong Aisheng 				ret &= ~ESDHC_MIX_CTRL_AC23EN;
6757dd109efSDong Aisheng 				ret |= SDHCI_TRNS_AUTO_CMD23;
6767dd109efSDong Aisheng 			}
6777dd109efSDong Aisheng 		} else {
6787dd109efSDong Aisheng 			ret = readw(host->ioaddr + SDHCI_TRANSFER_MODE);
6797dd109efSDong Aisheng 		}
6807dd109efSDong Aisheng 
6817dd109efSDong Aisheng 		return ret;
6827dd109efSDong Aisheng 	}
6837dd109efSDong Aisheng 
68495f25efeSWolfram Sang 	return readw(host->ioaddr + reg);
68595f25efeSWolfram Sang }
68695f25efeSWolfram Sang 
esdhc_writew_le(struct sdhci_host * host,u16 val,int reg)68795f25efeSWolfram Sang static void esdhc_writew_le(struct sdhci_host *host, u16 val, int reg)
68895f25efeSWolfram Sang {
68995f25efeSWolfram Sang 	struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
690070e6d3fSJisheng Zhang 	struct pltfm_imx_data *imx_data = sdhci_pltfm_priv(pltfm_host);
6910322191eSDong Aisheng 	u32 new_val = 0;
69295f25efeSWolfram Sang 
69395f25efeSWolfram Sang 	switch (reg) {
6940322191eSDong Aisheng 	case SDHCI_CLOCK_CONTROL:
6950322191eSDong Aisheng 		new_val = readl(host->ioaddr + ESDHC_VENDOR_SPEC);
6960322191eSDong Aisheng 		if (val & SDHCI_CLOCK_CARD_EN)
6970322191eSDong Aisheng 			new_val |= ESDHC_VENDOR_SPEC_FRC_SDCLK_ON;
6980322191eSDong Aisheng 		else
6990322191eSDong Aisheng 			new_val &= ~ESDHC_VENDOR_SPEC_FRC_SDCLK_ON;
7000322191eSDong Aisheng 		writel(new_val, host->ioaddr + ESDHC_VENDOR_SPEC);
701f581e909SHaibo Chen 		if (!(new_val & ESDHC_VENDOR_SPEC_FRC_SDCLK_ON))
702f581e909SHaibo Chen 			esdhc_wait_for_card_clock_gate_off(host);
7030322191eSDong Aisheng 		return;
7040322191eSDong Aisheng 	case SDHCI_HOST_CONTROL2:
7050322191eSDong Aisheng 		new_val = readl(host->ioaddr + ESDHC_VENDOR_SPEC);
7060322191eSDong Aisheng 		if (val & SDHCI_CTRL_VDD_180)
7070322191eSDong Aisheng 			new_val |= ESDHC_VENDOR_SPEC_VSELECT;
7080322191eSDong Aisheng 		else
7090322191eSDong Aisheng 			new_val &= ~ESDHC_VENDOR_SPEC_VSELECT;
7100322191eSDong Aisheng 		writel(new_val, host->ioaddr + ESDHC_VENDOR_SPEC);
711a0dbbdc2SHaibo Chen 		if (imx_data->socdata->flags & ESDHC_FLAG_STD_TUNING) {
712869f8a69SAdrian Hunter 			u32 v = readl(host->ioaddr + SDHCI_AUTO_CMD_STATUS);
7136e9fd28eSDong Aisheng 			u32 m = readl(host->ioaddr + ESDHC_MIX_CTRL);
7148b2bb0adSDong Aisheng 			if (val & SDHCI_CTRL_TUNED_CLK) {
7158b2bb0adSDong Aisheng 				v |= ESDHC_MIX_CTRL_SMPCLK_SEL;
7166e9fd28eSDong Aisheng 			} else {
7178b2bb0adSDong Aisheng 				v &= ~ESDHC_MIX_CTRL_SMPCLK_SEL;
7186e9fd28eSDong Aisheng 				m &= ~ESDHC_MIX_CTRL_FBCLK_SEL;
7196e9fd28eSDong Aisheng 			}
7206e9fd28eSDong Aisheng 
7218b2bb0adSDong Aisheng 			if (val & SDHCI_CTRL_EXEC_TUNING) {
7228b2bb0adSDong Aisheng 				v |= ESDHC_MIX_CTRL_EXE_TUNE;
7238b2bb0adSDong Aisheng 				m |= ESDHC_MIX_CTRL_FBCLK_SEL;
7248b2bb0adSDong Aisheng 			} else {
7258b2bb0adSDong Aisheng 				v &= ~ESDHC_MIX_CTRL_EXE_TUNE;
7268b2bb0adSDong Aisheng 			}
7276e9fd28eSDong Aisheng 
728869f8a69SAdrian Hunter 			writel(v, host->ioaddr + SDHCI_AUTO_CMD_STATUS);
7296e9fd28eSDong Aisheng 			writel(m, host->ioaddr + ESDHC_MIX_CTRL);
7306e9fd28eSDong Aisheng 		}
7310322191eSDong Aisheng 		return;
73295f25efeSWolfram Sang 	case SDHCI_TRANSFER_MODE:
733f47c4bbfSShawn Guo 		if ((imx_data->socdata->flags & ESDHC_FLAG_MULTIBLK_NO_INT)
73458ac8177SRichard Zhu 				&& (host->cmd->opcode == SD_IO_RW_EXTENDED)
73558ac8177SRichard Zhu 				&& (host->cmd->data->blocks > 1)
73658ac8177SRichard Zhu 				&& (host->cmd->data->flags & MMC_DATA_READ)) {
73758ac8177SRichard Zhu 			u32 v;
73860bf6396SShawn Guo 			v = readl(host->ioaddr + ESDHC_VENDOR_SPEC);
73960bf6396SShawn Guo 			v |= ESDHC_VENDOR_SPEC_SDIO_QUIRK;
74060bf6396SShawn Guo 			writel(v, host->ioaddr + ESDHC_VENDOR_SPEC);
74158ac8177SRichard Zhu 		}
74269f54698SShawn Guo 
7439d61c009SShawn Guo 		if (esdhc_is_usdhc(imx_data)) {
7443fbd4322SAndrew Gabbasov 			u32 wml;
74569f54698SShawn Guo 			u32 m = readl(host->ioaddr + ESDHC_MIX_CTRL);
7462a15f981SShawn Guo 			/* Swap AC23 bit */
7472a15f981SShawn Guo 			if (val & SDHCI_TRNS_AUTO_CMD23) {
7482a15f981SShawn Guo 				val &= ~SDHCI_TRNS_AUTO_CMD23;
7492a15f981SShawn Guo 				val |= ESDHC_MIX_CTRL_AC23EN;
7502a15f981SShawn Guo 			}
7512a15f981SShawn Guo 			m = val | (m & ~ESDHC_MIX_CTRL_SDHCI_MASK);
75269f54698SShawn Guo 			writel(m, host->ioaddr + ESDHC_MIX_CTRL);
7533fbd4322SAndrew Gabbasov 
7543fbd4322SAndrew Gabbasov 			/* Set watermark levels for PIO access to maximum value
7553fbd4322SAndrew Gabbasov 			 * (128 words) to accommodate full 512 bytes buffer.
7563fbd4322SAndrew Gabbasov 			 * For DMA access restore the levels to default value.
7573fbd4322SAndrew Gabbasov 			 */
7583fbd4322SAndrew Gabbasov 			m = readl(host->ioaddr + ESDHC_WTMK_LVL);
759e534b82fSHaibo Chen 			if (val & SDHCI_TRNS_DMA) {
7603fbd4322SAndrew Gabbasov 				wml = ESDHC_WTMK_LVL_WML_VAL_DEF;
761e534b82fSHaibo Chen 			} else {
762e534b82fSHaibo Chen 				u8 ctrl;
7633fbd4322SAndrew Gabbasov 				wml = ESDHC_WTMK_LVL_WML_VAL_MAX;
764e534b82fSHaibo Chen 
765e534b82fSHaibo Chen 				/*
766e534b82fSHaibo Chen 				 * Since already disable DMA mode, so also need
767e534b82fSHaibo Chen 				 * to clear the DMASEL. Otherwise, for standard
768e534b82fSHaibo Chen 				 * tuning, when send tuning command, usdhc will
769e534b82fSHaibo Chen 				 * still prefetch the ADMA script from wrong
770e534b82fSHaibo Chen 				 * DMA address, then we will see IOMMU report
771e534b82fSHaibo Chen 				 * some error which show lack of TLB mapping.
772e534b82fSHaibo Chen 				 */
773e534b82fSHaibo Chen 				ctrl = sdhci_readb(host, SDHCI_HOST_CONTROL);
774e534b82fSHaibo Chen 				ctrl &= ~SDHCI_CTRL_DMA_MASK;
775e534b82fSHaibo Chen 				sdhci_writeb(host, ctrl, SDHCI_HOST_CONTROL);
776e534b82fSHaibo Chen 			}
7773fbd4322SAndrew Gabbasov 			m &= ~(ESDHC_WTMK_LVL_RD_WML_MASK |
7783fbd4322SAndrew Gabbasov 			       ESDHC_WTMK_LVL_WR_WML_MASK);
7793fbd4322SAndrew Gabbasov 			m |= (wml << ESDHC_WTMK_LVL_RD_WML_SHIFT) |
7803fbd4322SAndrew Gabbasov 			     (wml << ESDHC_WTMK_LVL_WR_WML_SHIFT);
7813fbd4322SAndrew Gabbasov 			writel(m, host->ioaddr + ESDHC_WTMK_LVL);
78269f54698SShawn Guo 		} else {
78369f54698SShawn Guo 			/*
78469f54698SShawn Guo 			 * Postpone this write, we must do it together with a
78569f54698SShawn Guo 			 * command write that is down below.
78669f54698SShawn Guo 			 */
787e149860dSRichard Zhu 			imx_data->scratchpad = val;
78869f54698SShawn Guo 		}
78995f25efeSWolfram Sang 		return;
79095f25efeSWolfram Sang 	case SDHCI_COMMAND:
791361b8482SLucas Stach 		if (host->cmd->opcode == MMC_STOP_TRANSMISSION)
79258ac8177SRichard Zhu 			val |= SDHCI_CMD_ABORTCMD;
79395a2482aSShawn Guo 
794361b8482SLucas Stach 		if ((host->cmd->opcode == MMC_SET_BLOCK_COUNT) &&
795f47c4bbfSShawn Guo 		    (imx_data->socdata->flags & ESDHC_FLAG_MULTIBLK_NO_INT))
796361b8482SLucas Stach 			imx_data->multiblock_status = MULTIBLK_IN_PROCESS;
797361b8482SLucas Stach 
7989d61c009SShawn Guo 		if (esdhc_is_usdhc(imx_data))
79995a2482aSShawn Guo 			writel(val << 16,
80095a2482aSShawn Guo 			       host->ioaddr + SDHCI_TRANSFER_MODE);
80169f54698SShawn Guo 		else
802e149860dSRichard Zhu 			writel(val << 16 | imx_data->scratchpad,
80395f25efeSWolfram Sang 			       host->ioaddr + SDHCI_TRANSFER_MODE);
80495f25efeSWolfram Sang 		return;
80595f25efeSWolfram Sang 	case SDHCI_BLOCK_SIZE:
80695f25efeSWolfram Sang 		val &= ~SDHCI_MAKE_BLKSZ(0x7, 0);
80795f25efeSWolfram Sang 		break;
80895f25efeSWolfram Sang 	}
80995f25efeSWolfram Sang 	esdhc_clrset_le(host, 0xffff, val, reg);
81095f25efeSWolfram Sang }
81195f25efeSWolfram Sang 
esdhc_readb_le(struct sdhci_host * host,int reg)81277da3da0SAaron Brice static u8 esdhc_readb_le(struct sdhci_host *host, int reg)
81377da3da0SAaron Brice {
81477da3da0SAaron Brice 	u8 ret;
81577da3da0SAaron Brice 	u32 val;
81677da3da0SAaron Brice 
81777da3da0SAaron Brice 	switch (reg) {
81877da3da0SAaron Brice 	case SDHCI_HOST_CONTROL:
81977da3da0SAaron Brice 		val = readl(host->ioaddr + reg);
82077da3da0SAaron Brice 
82177da3da0SAaron Brice 		ret = val & SDHCI_CTRL_LED;
82277da3da0SAaron Brice 		ret |= (val >> 5) & SDHCI_CTRL_DMA_MASK;
82377da3da0SAaron Brice 		ret |= (val & ESDHC_CTRL_4BITBUS);
82477da3da0SAaron Brice 		ret |= (val & ESDHC_CTRL_8BITBUS) << 3;
82577da3da0SAaron Brice 		return ret;
82677da3da0SAaron Brice 	}
82777da3da0SAaron Brice 
82877da3da0SAaron Brice 	return readb(host->ioaddr + reg);
82977da3da0SAaron Brice }
83077da3da0SAaron Brice 
esdhc_writeb_le(struct sdhci_host * host,u8 val,int reg)83195f25efeSWolfram Sang static void esdhc_writeb_le(struct sdhci_host *host, u8 val, int reg)
83295f25efeSWolfram Sang {
8339a0985b7SWilson Callan 	struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
834070e6d3fSJisheng Zhang 	struct pltfm_imx_data *imx_data = sdhci_pltfm_priv(pltfm_host);
83581a0a8bcSBenoît Thébaudeau 	u32 new_val = 0;
836af51079eSSascha Hauer 	u32 mask;
83795f25efeSWolfram Sang 
83895f25efeSWolfram Sang 	switch (reg) {
83995f25efeSWolfram Sang 	case SDHCI_POWER_CONTROL:
84095f25efeSWolfram Sang 		/*
84195f25efeSWolfram Sang 		 * FSL put some DMA bits here
84295f25efeSWolfram Sang 		 * If your board has a regulator, code should be here
84395f25efeSWolfram Sang 		 */
84495f25efeSWolfram Sang 		return;
84595f25efeSWolfram Sang 	case SDHCI_HOST_CONTROL:
8466b40d182SShawn Guo 		/* FSL messed up here, so we need to manually compose it. */
847af51079eSSascha Hauer 		new_val = val & SDHCI_CTRL_LED;
8487122bbb0SMasanari Iida 		/* ensure the endianness */
84995f25efeSWolfram Sang 		new_val |= ESDHC_HOST_CONTROL_LE;
8509a0985b7SWilson Callan 		/* bits 8&9 are reserved on mx25 */
8519a0985b7SWilson Callan 		if (!is_imx25_esdhc(imx_data)) {
85295f25efeSWolfram Sang 			/* DMA mode bits are shifted */
85395f25efeSWolfram Sang 			new_val |= (val & SDHCI_CTRL_DMA_MASK) << 5;
8549a0985b7SWilson Callan 		}
85595f25efeSWolfram Sang 
856af51079eSSascha Hauer 		/*
857af51079eSSascha Hauer 		 * Do not touch buswidth bits here. This is done in
858af51079eSSascha Hauer 		 * esdhc_pltfm_bus_width.
859f6825748SMartin Fuzzey 		 * Do not touch the D3CD bit either which is used for the
860d04f8d5bSBenoît Thébaudeau 		 * SDIO interrupt erratum workaround.
861af51079eSSascha Hauer 		 */
862f6825748SMartin Fuzzey 		mask = 0xffff & ~(ESDHC_CTRL_BUSWIDTH_MASK | ESDHC_CTRL_D3CD);
863af51079eSSascha Hauer 
864af51079eSSascha Hauer 		esdhc_clrset_le(host, mask, new_val, reg);
86595f25efeSWolfram Sang 		return;
86681a0a8bcSBenoît Thébaudeau 	case SDHCI_SOFTWARE_RESET:
86781a0a8bcSBenoît Thébaudeau 		if (val & SDHCI_RESET_DATA)
86881a0a8bcSBenoît Thébaudeau 			new_val = readl(host->ioaddr + SDHCI_HOST_CONTROL);
86981a0a8bcSBenoît Thébaudeau 		break;
87095f25efeSWolfram Sang 	}
87195f25efeSWolfram Sang 	esdhc_clrset_le(host, 0xff, val, reg);
872913413c3SShawn Guo 
87381a0a8bcSBenoît Thébaudeau 	if (reg == SDHCI_SOFTWARE_RESET) {
87481a0a8bcSBenoît Thébaudeau 		if (val & SDHCI_RESET_ALL) {
875913413c3SShawn Guo 			/*
87681a0a8bcSBenoît Thébaudeau 			 * The esdhc has a design violation to SDHC spec which
87781a0a8bcSBenoît Thébaudeau 			 * tells that software reset should not affect card
87881a0a8bcSBenoît Thébaudeau 			 * detection circuit. But esdhc clears its SYSCTL
87981a0a8bcSBenoît Thébaudeau 			 * register bits [0..2] during the software reset. This
88081a0a8bcSBenoît Thébaudeau 			 * will stop those clocks that card detection circuit
88181a0a8bcSBenoît Thébaudeau 			 * relies on. To work around it, we turn the clocks on
88281a0a8bcSBenoît Thébaudeau 			 * back to keep card detection circuit functional.
883913413c3SShawn Guo 			 */
884913413c3SShawn Guo 			esdhc_clrset_le(host, 0x7, 0x7, ESDHC_SYSTEM_CONTROL);
88558c8c4fbSShawn Guo 			/*
88658c8c4fbSShawn Guo 			 * The reset on usdhc fails to clear MIX_CTRL register.
88758c8c4fbSShawn Guo 			 * Do it manually here.
88858c8c4fbSShawn Guo 			 */
889de5bdbffSDong Aisheng 			if (esdhc_is_usdhc(imx_data)) {
89081a0a8bcSBenoît Thébaudeau 				/*
89181a0a8bcSBenoît Thébaudeau 				 * the tuning bits should be kept during reset
89281a0a8bcSBenoît Thébaudeau 				 */
893d131a71cSDong Aisheng 				new_val = readl(host->ioaddr + ESDHC_MIX_CTRL);
894d131a71cSDong Aisheng 				writel(new_val & ESDHC_MIX_CTRL_TUNING_MASK,
895d131a71cSDong Aisheng 						host->ioaddr + ESDHC_MIX_CTRL);
896de5bdbffSDong Aisheng 				imx_data->is_ddr = 0;
897de5bdbffSDong Aisheng 			}
89881a0a8bcSBenoît Thébaudeau 		} else if (val & SDHCI_RESET_DATA) {
89981a0a8bcSBenoît Thébaudeau 			/*
90081a0a8bcSBenoît Thébaudeau 			 * The eSDHC DAT line software reset clears at least the
90181a0a8bcSBenoît Thébaudeau 			 * data transfer width on i.MX25, so make sure that the
90281a0a8bcSBenoît Thébaudeau 			 * Host Control register is unaffected.
90381a0a8bcSBenoît Thébaudeau 			 */
90481a0a8bcSBenoît Thébaudeau 			esdhc_clrset_le(host, 0xff, new_val,
90581a0a8bcSBenoît Thébaudeau 					SDHCI_HOST_CONTROL);
90681a0a8bcSBenoît Thébaudeau 		}
90758c8c4fbSShawn Guo 	}
90895f25efeSWolfram Sang }
90995f25efeSWolfram Sang 
esdhc_pltfm_get_max_clock(struct sdhci_host * host)9100ddf03c9SLucas Stach static unsigned int esdhc_pltfm_get_max_clock(struct sdhci_host *host)
9110ddf03c9SLucas Stach {
9120ddf03c9SLucas Stach 	struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
9130ddf03c9SLucas Stach 
914a974862fSDong Aisheng 	return pltfm_host->clock;
9150ddf03c9SLucas Stach }
9160ddf03c9SLucas Stach 
esdhc_pltfm_get_min_clock(struct sdhci_host * host)91795f25efeSWolfram Sang static unsigned int esdhc_pltfm_get_min_clock(struct sdhci_host *host)
91895f25efeSWolfram Sang {
91995f25efeSWolfram Sang 	struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
92095f25efeSWolfram Sang 
921a974862fSDong Aisheng 	return pltfm_host->clock / 256 / 16;
92295f25efeSWolfram Sang }
92395f25efeSWolfram Sang 
esdhc_pltfm_set_clock(struct sdhci_host * host,unsigned int clock)9248ba9580aSLucas Stach static inline void esdhc_pltfm_set_clock(struct sdhci_host *host,
9258ba9580aSLucas Stach 					 unsigned int clock)
9268ba9580aSLucas Stach {
9278ba9580aSLucas Stach 	struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
928070e6d3fSJisheng Zhang 	struct pltfm_imx_data *imx_data = sdhci_pltfm_priv(pltfm_host);
929a974862fSDong Aisheng 	unsigned int host_clock = pltfm_host->clock;
9305143c953SBenoît Thébaudeau 	int ddr_pre_div = imx_data->is_ddr ? 2 : 1;
9315143c953SBenoît Thébaudeau 	int pre_div = 1;
932d31fc00aSDong Aisheng 	int div = 1;
933f581e909SHaibo Chen 	int ret;
934fed2f6e2SDong Aisheng 	u32 temp, val;
9358ba9580aSLucas Stach 
9369d61c009SShawn Guo 	if (esdhc_is_usdhc(imx_data)) {
937fed2f6e2SDong Aisheng 		val = readl(host->ioaddr + ESDHC_VENDOR_SPEC);
938fed2f6e2SDong Aisheng 		writel(val & ~ESDHC_VENDOR_SPEC_FRC_SDCLK_ON,
939fed2f6e2SDong Aisheng 			host->ioaddr + ESDHC_VENDOR_SPEC);
940f581e909SHaibo Chen 		esdhc_wait_for_card_clock_gate_off(host);
941fed2f6e2SDong Aisheng 	}
94273e736f8SStefan Agner 
94373e736f8SStefan Agner 	if (clock == 0) {
94473e736f8SStefan Agner 		host->mmc->actual_clock = 0;
945373073efSRussell King 		return;
946fed2f6e2SDong Aisheng 	}
947d31fc00aSDong Aisheng 
948499ed50fSBenoît Thébaudeau 	/* For i.MX53 eSDHCv3, SYSCTL.SDCLKFS may not be set to 0. */
949499ed50fSBenoît Thébaudeau 	if (is_imx53_esdhc(imx_data)) {
950499ed50fSBenoît Thébaudeau 		/*
951499ed50fSBenoît Thébaudeau 		 * According to the i.MX53 reference manual, if DLLCTRL[10] can
952499ed50fSBenoît Thébaudeau 		 * be set, then the controller is eSDHCv3, else it is eSDHCv2.
953499ed50fSBenoît Thébaudeau 		 */
954499ed50fSBenoît Thébaudeau 		val = readl(host->ioaddr + ESDHC_DLL_CTRL);
955499ed50fSBenoît Thébaudeau 		writel(val | BIT(10), host->ioaddr + ESDHC_DLL_CTRL);
956499ed50fSBenoît Thébaudeau 		temp = readl(host->ioaddr + ESDHC_DLL_CTRL);
957499ed50fSBenoît Thébaudeau 		writel(val, host->ioaddr + ESDHC_DLL_CTRL);
958499ed50fSBenoît Thébaudeau 		if (temp & BIT(10))
959499ed50fSBenoît Thébaudeau 			pre_div = 2;
960499ed50fSBenoît Thébaudeau 	}
961499ed50fSBenoît Thébaudeau 
962d31fc00aSDong Aisheng 	temp = sdhci_readl(host, ESDHC_SYSTEM_CONTROL);
963d31fc00aSDong Aisheng 	temp &= ~(ESDHC_CLOCK_IPGEN | ESDHC_CLOCK_HCKEN | ESDHC_CLOCK_PEREN
964d31fc00aSDong Aisheng 		| ESDHC_CLOCK_MASK);
965d31fc00aSDong Aisheng 	sdhci_writel(host, temp, ESDHC_SYSTEM_CONTROL);
966d31fc00aSDong Aisheng 
9675ae4b0d8SGiulio Benetti 	if ((imx_data->socdata->flags & ESDHC_FLAG_ERR010450) &&
9685ae4b0d8SGiulio Benetti 	    (!(host->quirks2 & SDHCI_QUIRK2_NO_1_8_V))) {
969af6a50d4SBOUGH CHEN 		unsigned int max_clock;
970af6a50d4SBOUGH CHEN 
971af6a50d4SBOUGH CHEN 		max_clock = imx_data->is_ddr ? 45000000 : 150000000;
972af6a50d4SBOUGH CHEN 
973af6a50d4SBOUGH CHEN 		clock = min(clock, max_clock);
974af6a50d4SBOUGH CHEN 	}
975af6a50d4SBOUGH CHEN 
9765143c953SBenoît Thébaudeau 	while (host_clock / (16 * pre_div * ddr_pre_div) > clock &&
9775143c953SBenoît Thébaudeau 			pre_div < 256)
978d31fc00aSDong Aisheng 		pre_div *= 2;
979d31fc00aSDong Aisheng 
9805143c953SBenoît Thébaudeau 	while (host_clock / (div * pre_div * ddr_pre_div) > clock && div < 16)
981d31fc00aSDong Aisheng 		div++;
982d31fc00aSDong Aisheng 
9835143c953SBenoît Thébaudeau 	host->mmc->actual_clock = host_clock / (div * pre_div * ddr_pre_div);
984d31fc00aSDong Aisheng 	dev_dbg(mmc_dev(host->mmc), "desired SD clock: %d, actual: %d\n",
985e76b8559SDong Aisheng 		clock, host->mmc->actual_clock);
986d31fc00aSDong Aisheng 
987d31fc00aSDong Aisheng 	pre_div >>= 1;
988d31fc00aSDong Aisheng 	div--;
989d31fc00aSDong Aisheng 
990d31fc00aSDong Aisheng 	temp = sdhci_readl(host, ESDHC_SYSTEM_CONTROL);
991d31fc00aSDong Aisheng 	temp |= (ESDHC_CLOCK_IPGEN | ESDHC_CLOCK_HCKEN | ESDHC_CLOCK_PEREN
992d31fc00aSDong Aisheng 		| (div << ESDHC_DIVIDER_SHIFT)
993d31fc00aSDong Aisheng 		| (pre_div << ESDHC_PREDIV_SHIFT));
994d31fc00aSDong Aisheng 	sdhci_writel(host, temp, ESDHC_SYSTEM_CONTROL);
995fed2f6e2SDong Aisheng 
996f581e909SHaibo Chen 	/* need to wait the bit 3 of the PRSSTAT to be set, make sure card clock is stable */
997f581e909SHaibo Chen 	ret = readl_poll_timeout(host->ioaddr + ESDHC_PRSSTAT, temp,
998f581e909SHaibo Chen 				(temp & ESDHC_CLOCK_STABLE), 2, 100);
999f581e909SHaibo Chen 	if (ret == -ETIMEDOUT)
1000f581e909SHaibo Chen 		dev_warn(mmc_dev(host->mmc), "card clock still not stable in 100us!.\n");
1001f581e909SHaibo Chen 
10029d61c009SShawn Guo 	if (esdhc_is_usdhc(imx_data)) {
1003fed2f6e2SDong Aisheng 		val = readl(host->ioaddr + ESDHC_VENDOR_SPEC);
1004fed2f6e2SDong Aisheng 		writel(val | ESDHC_VENDOR_SPEC_FRC_SDCLK_ON,
1005fed2f6e2SDong Aisheng 			host->ioaddr + ESDHC_VENDOR_SPEC);
1006fed2f6e2SDong Aisheng 	}
1007fed2f6e2SDong Aisheng 
10088ba9580aSLucas Stach }
10098ba9580aSLucas Stach 
esdhc_pltfm_get_ro(struct sdhci_host * host)1010913413c3SShawn Guo static unsigned int esdhc_pltfm_get_ro(struct sdhci_host *host)
1011913413c3SShawn Guo {
1012842afc02SShawn Guo 	struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
1013070e6d3fSJisheng Zhang 	struct pltfm_imx_data *imx_data = sdhci_pltfm_priv(pltfm_host);
1014842afc02SShawn Guo 	struct esdhc_platform_data *boarddata = &imx_data->boarddata;
1015913413c3SShawn Guo 
1016913413c3SShawn Guo 	switch (boarddata->wp_type) {
1017913413c3SShawn Guo 	case ESDHC_WP_GPIO:
1018fbe5fdd1SShawn Guo 		return mmc_gpio_get_ro(host->mmc);
1019913413c3SShawn Guo 	case ESDHC_WP_CONTROLLER:
1020913413c3SShawn Guo 		return !(readl(host->ioaddr + SDHCI_PRESENT_STATE) &
1021913413c3SShawn Guo 			       SDHCI_WRITE_PROTECT);
1022913413c3SShawn Guo 	case ESDHC_WP_NONE:
1023913413c3SShawn Guo 		break;
1024913413c3SShawn Guo 	}
1025913413c3SShawn Guo 
1026913413c3SShawn Guo 	return -ENOSYS;
1027913413c3SShawn Guo }
1028913413c3SShawn Guo 
esdhc_pltfm_set_bus_width(struct sdhci_host * host,int width)10292317f56cSRussell King static void esdhc_pltfm_set_bus_width(struct sdhci_host *host, int width)
1030af51079eSSascha Hauer {
1031af51079eSSascha Hauer 	u32 ctrl;
1032af51079eSSascha Hauer 
1033af51079eSSascha Hauer 	switch (width) {
1034af51079eSSascha Hauer 	case MMC_BUS_WIDTH_8:
1035af51079eSSascha Hauer 		ctrl = ESDHC_CTRL_8BITBUS;
1036af51079eSSascha Hauer 		break;
1037af51079eSSascha Hauer 	case MMC_BUS_WIDTH_4:
1038af51079eSSascha Hauer 		ctrl = ESDHC_CTRL_4BITBUS;
1039af51079eSSascha Hauer 		break;
1040af51079eSSascha Hauer 	default:
1041af51079eSSascha Hauer 		ctrl = 0;
1042af51079eSSascha Hauer 		break;
1043af51079eSSascha Hauer 	}
1044af51079eSSascha Hauer 
1045af51079eSSascha Hauer 	esdhc_clrset_le(host, ESDHC_CTRL_BUSWIDTH_MASK, ctrl,
1046af51079eSSascha Hauer 			SDHCI_HOST_CONTROL);
1047af51079eSSascha Hauer }
1048af51079eSSascha Hauer 
esdhc_reset_tuning(struct sdhci_host * host)10494fb27869SHaibo Chen static void esdhc_reset_tuning(struct sdhci_host *host)
10504fb27869SHaibo Chen {
10514fb27869SHaibo Chen 	struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
10524fb27869SHaibo Chen 	struct pltfm_imx_data *imx_data = sdhci_pltfm_priv(pltfm_host);
10534fb27869SHaibo Chen 	u32 ctrl;
10544fb27869SHaibo Chen 	int ret;
10554fb27869SHaibo Chen 
10564fb27869SHaibo Chen 	/* Reset the tuning circuit */
10574fb27869SHaibo Chen 	if (esdhc_is_usdhc(imx_data)) {
10584fb27869SHaibo Chen 		ctrl = readl(host->ioaddr + ESDHC_MIX_CTRL);
1059c8c49a5aSHaibo Chen 		ctrl &= ~ESDHC_MIX_CTRL_AUTO_TUNE_EN;
1060c8c49a5aSHaibo Chen 		if (imx_data->socdata->flags & ESDHC_FLAG_MAN_TUNING) {
10614fb27869SHaibo Chen 			ctrl &= ~ESDHC_MIX_CTRL_SMPCLK_SEL;
10624fb27869SHaibo Chen 			ctrl &= ~ESDHC_MIX_CTRL_FBCLK_SEL;
10634fb27869SHaibo Chen 			writel(ctrl, host->ioaddr + ESDHC_MIX_CTRL);
10644fb27869SHaibo Chen 			writel(0, host->ioaddr + ESDHC_TUNE_CTRL_STATUS);
10654fb27869SHaibo Chen 		} else if (imx_data->socdata->flags & ESDHC_FLAG_STD_TUNING) {
1066c8c49a5aSHaibo Chen 			writel(ctrl, host->ioaddr + ESDHC_MIX_CTRL);
10674fb27869SHaibo Chen 			ctrl = readl(host->ioaddr + SDHCI_AUTO_CMD_STATUS);
10684fb27869SHaibo Chen 			ctrl &= ~ESDHC_MIX_CTRL_SMPCLK_SEL;
10694fb27869SHaibo Chen 			ctrl &= ~ESDHC_MIX_CTRL_EXE_TUNE;
10704fb27869SHaibo Chen 			writel(ctrl, host->ioaddr + SDHCI_AUTO_CMD_STATUS);
10714fb27869SHaibo Chen 			/* Make sure ESDHC_MIX_CTRL_EXE_TUNE cleared */
10724fb27869SHaibo Chen 			ret = readl_poll_timeout(host->ioaddr + SDHCI_AUTO_CMD_STATUS,
10734fb27869SHaibo Chen 				ctrl, !(ctrl & ESDHC_MIX_CTRL_EXE_TUNE), 1, 50);
10744fb27869SHaibo Chen 			if (ret == -ETIMEDOUT)
10754fb27869SHaibo Chen 				dev_warn(mmc_dev(host->mmc),
10764fb27869SHaibo Chen 				 "Warning! clear execute tuning bit failed\n");
10774fb27869SHaibo Chen 			/*
10784fb27869SHaibo Chen 			 * SDHCI_INT_DATA_AVAIL is W1C bit, set this bit will clear the
10794fb27869SHaibo Chen 			 * usdhc IP internal logic flag execute_tuning_with_clr_buf, which
10804fb27869SHaibo Chen 			 * will finally make sure the normal data transfer logic correct.
10814fb27869SHaibo Chen 			 */
10824fb27869SHaibo Chen 			ctrl = readl(host->ioaddr + SDHCI_INT_STATUS);
10834fb27869SHaibo Chen 			ctrl |= SDHCI_INT_DATA_AVAIL;
10844fb27869SHaibo Chen 			writel(ctrl, host->ioaddr + SDHCI_INT_STATUS);
10854fb27869SHaibo Chen 		}
10864fb27869SHaibo Chen 	}
10874fb27869SHaibo Chen }
10884fb27869SHaibo Chen 
usdhc_init_card(struct mmc_host * mmc,struct mmc_card * card)108952e4c32bSHaibo Chen static void usdhc_init_card(struct mmc_host *mmc, struct mmc_card *card)
109052e4c32bSHaibo Chen {
109152e4c32bSHaibo Chen 	struct sdhci_host *host = mmc_priv(mmc);
109252e4c32bSHaibo Chen 	struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
109352e4c32bSHaibo Chen 	struct pltfm_imx_data *imx_data = sdhci_pltfm_priv(pltfm_host);
109452e4c32bSHaibo Chen 
109552e4c32bSHaibo Chen 	imx_data->init_card_type = card->type;
109652e4c32bSHaibo Chen }
109752e4c32bSHaibo Chen 
usdhc_execute_tuning(struct mmc_host * mmc,u32 opcode)1098de3e1dd0SBOUGH CHEN static int usdhc_execute_tuning(struct mmc_host *mmc, u32 opcode)
1099de3e1dd0SBOUGH CHEN {
1100de3e1dd0SBOUGH CHEN 	struct sdhci_host *host = mmc_priv(mmc);
1101c8c49a5aSHaibo Chen 	int err;
1102de3e1dd0SBOUGH CHEN 
1103de3e1dd0SBOUGH CHEN 	/*
1104de3e1dd0SBOUGH CHEN 	 * i.MX uSDHC internally already uses a fixed optimized timing for
1105de3e1dd0SBOUGH CHEN 	 * DDR50, normally does not require tuning for DDR50 mode.
1106de3e1dd0SBOUGH CHEN 	 */
1107de3e1dd0SBOUGH CHEN 	if (host->timing == MMC_TIMING_UHS_DDR50)
1108de3e1dd0SBOUGH CHEN 		return 0;
1109de3e1dd0SBOUGH CHEN 
11104fb27869SHaibo Chen 	/*
11114fb27869SHaibo Chen 	 * Reset tuning circuit logic. If not, the previous tuning result
11124fb27869SHaibo Chen 	 * will impact current tuning, make current tuning can't set the
11134fb27869SHaibo Chen 	 * correct delay cell.
11144fb27869SHaibo Chen 	 */
11154fb27869SHaibo Chen 	esdhc_reset_tuning(host);
1116c8c49a5aSHaibo Chen 	err = sdhci_execute_tuning(mmc, opcode);
1117c8c49a5aSHaibo Chen 	/* If tuning done, enable auto tuning */
1118c8c49a5aSHaibo Chen 	if (!err && !host->tuning_err)
1119c8c49a5aSHaibo Chen 		usdhc_auto_tuning_mode_sel_and_en(host);
1120c8c49a5aSHaibo Chen 
1121c8c49a5aSHaibo Chen 	return err;
1122de3e1dd0SBOUGH CHEN }
1123de3e1dd0SBOUGH CHEN 
esdhc_prepare_tuning(struct sdhci_host * host,u32 val)11240322191eSDong Aisheng static void esdhc_prepare_tuning(struct sdhci_host *host, u32 val)
11250322191eSDong Aisheng {
11260322191eSDong Aisheng 	u32 reg;
11270ac4f496SHaibo Chen 	u8 sw_rst;
11280ac4f496SHaibo Chen 	int ret;
11290322191eSDong Aisheng 
11300322191eSDong Aisheng 	/* FIXME: delay a bit for card to be ready for next tuning due to errors */
11310322191eSDong Aisheng 	mdelay(1);
11320322191eSDong Aisheng 
11330ac4f496SHaibo Chen 	/* IC suggest to reset USDHC before every tuning command */
11340ac4f496SHaibo Chen 	esdhc_clrset_le(host, 0xff, SDHCI_RESET_ALL, SDHCI_SOFTWARE_RESET);
11350ac4f496SHaibo Chen 	ret = readb_poll_timeout(host->ioaddr + SDHCI_SOFTWARE_RESET, sw_rst,
11360ac4f496SHaibo Chen 				!(sw_rst & SDHCI_RESET_ALL), 10, 100);
11370ac4f496SHaibo Chen 	if (ret == -ETIMEDOUT)
11380ac4f496SHaibo Chen 		dev_warn(mmc_dev(host->mmc),
11390ac4f496SHaibo Chen 		"warning! RESET_ALL never complete before sending tuning command\n");
11400ac4f496SHaibo Chen 
11410322191eSDong Aisheng 	reg = readl(host->ioaddr + ESDHC_MIX_CTRL);
11420322191eSDong Aisheng 	reg |= ESDHC_MIX_CTRL_EXE_TUNE | ESDHC_MIX_CTRL_SMPCLK_SEL |
11430322191eSDong Aisheng 			ESDHC_MIX_CTRL_FBCLK_SEL;
11440322191eSDong Aisheng 	writel(reg, host->ioaddr + ESDHC_MIX_CTRL);
11450322191eSDong Aisheng 	writel(val << 8, host->ioaddr + ESDHC_TUNE_CTRL_STATUS);
11460322191eSDong Aisheng 	dev_dbg(mmc_dev(host->mmc),
1147d04f8d5bSBenoît Thébaudeau 		"tuning with delay 0x%x ESDHC_TUNE_CTRL_STATUS 0x%x\n",
11480322191eSDong Aisheng 			val, readl(host->ioaddr + ESDHC_TUNE_CTRL_STATUS));
11490322191eSDong Aisheng }
11500322191eSDong Aisheng 
esdhc_post_tuning(struct sdhci_host * host)11510322191eSDong Aisheng static void esdhc_post_tuning(struct sdhci_host *host)
11520322191eSDong Aisheng {
11530322191eSDong Aisheng 	u32 reg;
11540322191eSDong Aisheng 
11550322191eSDong Aisheng 	reg = readl(host->ioaddr + ESDHC_MIX_CTRL);
11560322191eSDong Aisheng 	reg &= ~ESDHC_MIX_CTRL_EXE_TUNE;
11570322191eSDong Aisheng 	writel(reg, host->ioaddr + ESDHC_MIX_CTRL);
11580322191eSDong Aisheng }
11590322191eSDong Aisheng 
1160541a95e6SHaibo Chen /*
1161541a95e6SHaibo Chen  * find the largest pass window, and use the average delay of this
1162541a95e6SHaibo Chen  * largest window to get the best timing.
1163541a95e6SHaibo Chen  */
esdhc_executing_tuning(struct sdhci_host * host,u32 opcode)11640322191eSDong Aisheng static int esdhc_executing_tuning(struct sdhci_host *host, u32 opcode)
11650322191eSDong Aisheng {
11660322191eSDong Aisheng 	int min, max, avg, ret;
1167541a95e6SHaibo Chen 	int win_length, target_min, target_max, target_win_length;
11680322191eSDong Aisheng 
11690322191eSDong Aisheng 	min = ESDHC_TUNE_CTRL_MIN;
1170541a95e6SHaibo Chen 	max = ESDHC_TUNE_CTRL_MIN;
1171541a95e6SHaibo Chen 	target_win_length = 0;
1172541a95e6SHaibo Chen 	while (max < ESDHC_TUNE_CTRL_MAX) {
1173541a95e6SHaibo Chen 		/* find the mininum delay first which can pass tuning */
11740322191eSDong Aisheng 		while (min < ESDHC_TUNE_CTRL_MAX) {
11750322191eSDong Aisheng 			esdhc_prepare_tuning(host, min);
11769979dbe5SChaotian Jing 			if (!mmc_send_tuning(host->mmc, opcode, NULL))
11770322191eSDong Aisheng 				break;
11780322191eSDong Aisheng 			min += ESDHC_TUNE_CTRL_STEP;
11790322191eSDong Aisheng 		}
11800322191eSDong Aisheng 
11810322191eSDong Aisheng 		/* find the maxinum delay which can not pass tuning */
11820322191eSDong Aisheng 		max = min + ESDHC_TUNE_CTRL_STEP;
11830322191eSDong Aisheng 		while (max < ESDHC_TUNE_CTRL_MAX) {
11840322191eSDong Aisheng 			esdhc_prepare_tuning(host, max);
11859979dbe5SChaotian Jing 			if (mmc_send_tuning(host->mmc, opcode, NULL)) {
11860322191eSDong Aisheng 				max -= ESDHC_TUNE_CTRL_STEP;
11870322191eSDong Aisheng 				break;
11880322191eSDong Aisheng 			}
11890322191eSDong Aisheng 			max += ESDHC_TUNE_CTRL_STEP;
11900322191eSDong Aisheng 		}
11910322191eSDong Aisheng 
1192541a95e6SHaibo Chen 		win_length = max - min + 1;
1193541a95e6SHaibo Chen 		/* get the largest pass window */
1194541a95e6SHaibo Chen 		if (win_length > target_win_length) {
1195541a95e6SHaibo Chen 			target_win_length = win_length;
1196541a95e6SHaibo Chen 			target_min = min;
1197541a95e6SHaibo Chen 			target_max = max;
1198541a95e6SHaibo Chen 		}
1199541a95e6SHaibo Chen 
1200541a95e6SHaibo Chen 		/* continue to find the next pass window */
1201541a95e6SHaibo Chen 		min = max + ESDHC_TUNE_CTRL_STEP;
1202541a95e6SHaibo Chen 	}
1203541a95e6SHaibo Chen 
12040322191eSDong Aisheng 	/* use average delay to get the best timing */
1205541a95e6SHaibo Chen 	avg = (target_min + target_max) / 2;
12060322191eSDong Aisheng 	esdhc_prepare_tuning(host, avg);
12079979dbe5SChaotian Jing 	ret = mmc_send_tuning(host->mmc, opcode, NULL);
12080322191eSDong Aisheng 	esdhc_post_tuning(host);
12090322191eSDong Aisheng 
1210d04f8d5bSBenoît Thébaudeau 	dev_dbg(mmc_dev(host->mmc), "tuning %s at 0x%x ret %d\n",
12110322191eSDong Aisheng 		ret ? "failed" : "passed", avg, ret);
12120322191eSDong Aisheng 
12130322191eSDong Aisheng 	return ret;
12140322191eSDong Aisheng }
12150322191eSDong Aisheng 
esdhc_hs400_enhanced_strobe(struct mmc_host * mmc,struct mmc_ios * ios)1216029e2476SBOUGH CHEN static void esdhc_hs400_enhanced_strobe(struct mmc_host *mmc, struct mmc_ios *ios)
1217029e2476SBOUGH CHEN {
1218029e2476SBOUGH CHEN 	struct sdhci_host *host = mmc_priv(mmc);
1219029e2476SBOUGH CHEN 	u32 m;
1220029e2476SBOUGH CHEN 
1221029e2476SBOUGH CHEN 	m = readl(host->ioaddr + ESDHC_MIX_CTRL);
1222029e2476SBOUGH CHEN 	if (ios->enhanced_strobe)
1223029e2476SBOUGH CHEN 		m |= ESDHC_MIX_CTRL_HS400_ES_EN;
1224029e2476SBOUGH CHEN 	else
1225029e2476SBOUGH CHEN 		m &= ~ESDHC_MIX_CTRL_HS400_ES_EN;
1226029e2476SBOUGH CHEN 	writel(m, host->ioaddr + ESDHC_MIX_CTRL);
1227029e2476SBOUGH CHEN }
1228029e2476SBOUGH CHEN 
esdhc_change_pinstate(struct sdhci_host * host,unsigned int uhs)1229ad93220dSDong Aisheng static int esdhc_change_pinstate(struct sdhci_host *host,
1230ad93220dSDong Aisheng 						unsigned int uhs)
1231ad93220dSDong Aisheng {
1232ad93220dSDong Aisheng 	struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
1233070e6d3fSJisheng Zhang 	struct pltfm_imx_data *imx_data = sdhci_pltfm_priv(pltfm_host);
1234ad93220dSDong Aisheng 	struct pinctrl_state *pinctrl;
1235ad93220dSDong Aisheng 
1236ad93220dSDong Aisheng 	dev_dbg(mmc_dev(host->mmc), "change pinctrl state for uhs %d\n", uhs);
1237ad93220dSDong Aisheng 
1238ad93220dSDong Aisheng 	if (IS_ERR(imx_data->pinctrl) ||
1239ad93220dSDong Aisheng 		IS_ERR(imx_data->pins_100mhz) ||
1240ad93220dSDong Aisheng 		IS_ERR(imx_data->pins_200mhz))
1241ad93220dSDong Aisheng 		return -EINVAL;
1242ad93220dSDong Aisheng 
1243ad93220dSDong Aisheng 	switch (uhs) {
1244ad93220dSDong Aisheng 	case MMC_TIMING_UHS_SDR50:
12459f327845SHaibo Chen 	case MMC_TIMING_UHS_DDR50:
1246ad93220dSDong Aisheng 		pinctrl = imx_data->pins_100mhz;
1247ad93220dSDong Aisheng 		break;
1248ad93220dSDong Aisheng 	case MMC_TIMING_UHS_SDR104:
1249429a5b45SDong Aisheng 	case MMC_TIMING_MMC_HS200:
125028b07674SHaibo Chen 	case MMC_TIMING_MMC_HS400:
1251ad93220dSDong Aisheng 		pinctrl = imx_data->pins_200mhz;
1252ad93220dSDong Aisheng 		break;
1253ad93220dSDong Aisheng 	default:
1254ad93220dSDong Aisheng 		/* back to default state for other legacy timing */
12552480b720SUlf Hansson 		return pinctrl_select_default_state(mmc_dev(host->mmc));
1256ad93220dSDong Aisheng 	}
1257ad93220dSDong Aisheng 
1258ad93220dSDong Aisheng 	return pinctrl_select_state(imx_data->pinctrl, pinctrl);
1259ad93220dSDong Aisheng }
1260ad93220dSDong Aisheng 
126128b07674SHaibo Chen /*
1262d04f8d5bSBenoît Thébaudeau  * For HS400 eMMC, there is a data_strobe line. This signal is generated
126328b07674SHaibo Chen  * by the device and used for data output and CRC status response output
126428b07674SHaibo Chen  * in HS400 mode. The frequency of this signal follows the frequency of
1265d04f8d5bSBenoît Thébaudeau  * CLK generated by host. The host receives the data which is aligned to the
126628b07674SHaibo Chen  * edge of data_strobe line. Due to the time delay between CLK line and
126728b07674SHaibo Chen  * data_strobe line, if the delay time is larger than one clock cycle,
1268d04f8d5bSBenoît Thébaudeau  * then CLK and data_strobe line will be misaligned, read error shows up.
126928b07674SHaibo Chen  */
esdhc_set_strobe_dll(struct sdhci_host * host)127028b07674SHaibo Chen static void esdhc_set_strobe_dll(struct sdhci_host *host)
127128b07674SHaibo Chen {
12725bd2acdcSHaibo Chen 	struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
12735bd2acdcSHaibo Chen 	struct pltfm_imx_data *imx_data = sdhci_pltfm_priv(pltfm_host);
12745bd2acdcSHaibo Chen 	u32 strobe_delay;
127528b07674SHaibo Chen 	u32 v;
1276373e800bSHaibo Chen 	int ret;
127728b07674SHaibo Chen 
12787ac6da26SDong Aisheng 	/* disable clock before enabling strobe dll */
12797ac6da26SDong Aisheng 	writel(readl(host->ioaddr + ESDHC_VENDOR_SPEC) &
12807ac6da26SDong Aisheng 		~ESDHC_VENDOR_SPEC_FRC_SDCLK_ON,
12817ac6da26SDong Aisheng 		host->ioaddr + ESDHC_VENDOR_SPEC);
1282f581e909SHaibo Chen 	esdhc_wait_for_card_clock_gate_off(host);
12837ac6da26SDong Aisheng 
128428b07674SHaibo Chen 	/* force a reset on strobe dll */
128528b07674SHaibo Chen 	writel(ESDHC_STROBE_DLL_CTRL_RESET,
128628b07674SHaibo Chen 		host->ioaddr + ESDHC_STROBE_DLL_CTRL);
12872eaf5a53SBOUGH CHEN 	/* clear the reset bit on strobe dll before any setting */
12882eaf5a53SBOUGH CHEN 	writel(0, host->ioaddr + ESDHC_STROBE_DLL_CTRL);
12892eaf5a53SBOUGH CHEN 
129028b07674SHaibo Chen 	/*
129128b07674SHaibo Chen 	 * enable strobe dll ctrl and adjust the delay target
129228b07674SHaibo Chen 	 * for the uSDHC loopback read clock
129328b07674SHaibo Chen 	 */
12945bd2acdcSHaibo Chen 	if (imx_data->boarddata.strobe_dll_delay_target)
12955bd2acdcSHaibo Chen 		strobe_delay = imx_data->boarddata.strobe_dll_delay_target;
12965bd2acdcSHaibo Chen 	else
12975bd2acdcSHaibo Chen 		strobe_delay = ESDHC_STROBE_DLL_CTRL_SLV_DLY_TARGET_DEFAULT;
129828b07674SHaibo Chen 	v = ESDHC_STROBE_DLL_CTRL_ENABLE |
12992eaf5a53SBOUGH CHEN 		ESDHC_STROBE_DLL_CTRL_SLV_UPDATE_INT_DEFAULT |
13005bd2acdcSHaibo Chen 		(strobe_delay << ESDHC_STROBE_DLL_CTRL_SLV_DLY_TARGET_SHIFT);
130128b07674SHaibo Chen 	writel(v, host->ioaddr + ESDHC_STROBE_DLL_CTRL);
1302373e800bSHaibo Chen 
1303373e800bSHaibo Chen 	/* wait max 50us to get the REF/SLV lock */
1304373e800bSHaibo Chen 	ret = readl_poll_timeout(host->ioaddr + ESDHC_STROBE_DLL_STATUS, v,
1305373e800bSHaibo Chen 		((v & ESDHC_STROBE_DLL_STS_REF_LOCK) && (v & ESDHC_STROBE_DLL_STS_SLV_LOCK)), 1, 50);
1306373e800bSHaibo Chen 	if (ret == -ETIMEDOUT)
130728b07674SHaibo Chen 		dev_warn(mmc_dev(host->mmc),
1308373e800bSHaibo Chen 		"warning! HS400 strobe DLL status REF/SLV not lock in 50us, STROBE DLL status is %x!\n", v);
130928b07674SHaibo Chen }
131028b07674SHaibo Chen 
esdhc_set_uhs_signaling(struct sdhci_host * host,unsigned timing)1311850a29b8SRussell King static void esdhc_set_uhs_signaling(struct sdhci_host *host, unsigned timing)
1312ad93220dSDong Aisheng {
131328b07674SHaibo Chen 	u32 m;
1314ad93220dSDong Aisheng 	struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
1315070e6d3fSJisheng Zhang 	struct pltfm_imx_data *imx_data = sdhci_pltfm_priv(pltfm_host);
1316602519b2SDong Aisheng 	struct esdhc_platform_data *boarddata = &imx_data->boarddata;
1317ad93220dSDong Aisheng 
131828b07674SHaibo Chen 	/* disable ddr mode and disable HS400 mode */
131928b07674SHaibo Chen 	m = readl(host->ioaddr + ESDHC_MIX_CTRL);
132028b07674SHaibo Chen 	m &= ~(ESDHC_MIX_CTRL_DDREN | ESDHC_MIX_CTRL_HS400_EN);
132128b07674SHaibo Chen 	imx_data->is_ddr = 0;
132228b07674SHaibo Chen 
1323850a29b8SRussell King 	switch (timing) {
1324ad93220dSDong Aisheng 	case MMC_TIMING_UHS_SDR12:
1325ad93220dSDong Aisheng 	case MMC_TIMING_UHS_SDR25:
1326ad93220dSDong Aisheng 	case MMC_TIMING_UHS_SDR50:
1327ad93220dSDong Aisheng 	case MMC_TIMING_UHS_SDR104:
1328de0a0decSBOUGH CHEN 	case MMC_TIMING_MMC_HS:
1329429a5b45SDong Aisheng 	case MMC_TIMING_MMC_HS200:
133028b07674SHaibo Chen 		writel(m, host->ioaddr + ESDHC_MIX_CTRL);
1331ad93220dSDong Aisheng 		break;
1332ad93220dSDong Aisheng 	case MMC_TIMING_UHS_DDR50:
133369f5bf38SAisheng Dong 	case MMC_TIMING_MMC_DDR52:
133428b07674SHaibo Chen 		m |= ESDHC_MIX_CTRL_DDREN;
133528b07674SHaibo Chen 		writel(m, host->ioaddr + ESDHC_MIX_CTRL);
1336de5bdbffSDong Aisheng 		imx_data->is_ddr = 1;
1337602519b2SDong Aisheng 		if (boarddata->delay_line) {
1338602519b2SDong Aisheng 			u32 v;
1339602519b2SDong Aisheng 			v = boarddata->delay_line <<
1340602519b2SDong Aisheng 				ESDHC_DLL_OVERRIDE_VAL_SHIFT |
1341602519b2SDong Aisheng 				(1 << ESDHC_DLL_OVERRIDE_EN_SHIFT);
1342602519b2SDong Aisheng 			if (is_imx53_esdhc(imx_data))
1343602519b2SDong Aisheng 				v <<= 1;
1344602519b2SDong Aisheng 			writel(v, host->ioaddr + ESDHC_DLL_CTRL);
1345602519b2SDong Aisheng 		}
1346ad93220dSDong Aisheng 		break;
134728b07674SHaibo Chen 	case MMC_TIMING_MMC_HS400:
134828b07674SHaibo Chen 		m |= ESDHC_MIX_CTRL_DDREN | ESDHC_MIX_CTRL_HS400_EN;
134928b07674SHaibo Chen 		writel(m, host->ioaddr + ESDHC_MIX_CTRL);
135028b07674SHaibo Chen 		imx_data->is_ddr = 1;
13517ac6da26SDong Aisheng 		/* update clock after enable DDR for strobe DLL lock */
13527ac6da26SDong Aisheng 		host->ops->set_clock(host, host->clock);
135328b07674SHaibo Chen 		esdhc_set_strobe_dll(host);
135428b07674SHaibo Chen 		break;
1355d9370424SHaibo Chen 	case MMC_TIMING_LEGACY:
1356d9370424SHaibo Chen 	default:
1357d9370424SHaibo Chen 		esdhc_reset_tuning(host);
1358d9370424SHaibo Chen 		break;
1359ad93220dSDong Aisheng 	}
1360ad93220dSDong Aisheng 
1361850a29b8SRussell King 	esdhc_change_pinstate(host, timing);
1362ad93220dSDong Aisheng }
1363ad93220dSDong Aisheng 
esdhc_reset(struct sdhci_host * host,u8 mask)13640718e59aSRussell King static void esdhc_reset(struct sdhci_host *host, u8 mask)
13650718e59aSRussell King {
1366fb1dec44SBrian Norris 	sdhci_and_cqhci_reset(host, mask);
13670718e59aSRussell King 
13680718e59aSRussell King 	sdhci_writel(host, host->ier, SDHCI_INT_ENABLE);
13690718e59aSRussell King 	sdhci_writel(host, host->ier, SDHCI_SIGNAL_ENABLE);
13700718e59aSRussell King }
13710718e59aSRussell King 
esdhc_get_max_timeout_count(struct sdhci_host * host)137210fd0ad9SAisheng Dong static unsigned int esdhc_get_max_timeout_count(struct sdhci_host *host)
137310fd0ad9SAisheng Dong {
137410fd0ad9SAisheng Dong 	struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
1375070e6d3fSJisheng Zhang 	struct pltfm_imx_data *imx_data = sdhci_pltfm_priv(pltfm_host);
137610fd0ad9SAisheng Dong 
1377d04f8d5bSBenoît Thébaudeau 	/* Doc Erratum: the uSDHC actual maximum timeout count is 1 << 29 */
13782fb0b02bSHaibo Chen 	return esdhc_is_usdhc(imx_data) ? 1 << 29 : 1 << 27;
137910fd0ad9SAisheng Dong }
138010fd0ad9SAisheng Dong 
esdhc_set_timeout(struct sdhci_host * host,struct mmc_command * cmd)1381e33eb8e2SAisheng Dong static void esdhc_set_timeout(struct sdhci_host *host, struct mmc_command *cmd)
1382e33eb8e2SAisheng Dong {
1383e33eb8e2SAisheng Dong 	struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
1384070e6d3fSJisheng Zhang 	struct pltfm_imx_data *imx_data = sdhci_pltfm_priv(pltfm_host);
1385e33eb8e2SAisheng Dong 
1386e33eb8e2SAisheng Dong 	/* use maximum timeout counter */
1387a215186dSHaibo Chen 	esdhc_clrset_le(host, ESDHC_SYS_CTRL_DTOCV_MASK,
1388a215186dSHaibo Chen 			esdhc_is_usdhc(imx_data) ? 0xF : 0xE,
1389e33eb8e2SAisheng Dong 			SDHCI_TIMEOUT_CONTROL);
1390e33eb8e2SAisheng Dong }
1391e33eb8e2SAisheng Dong 
esdhc_cqhci_irq(struct sdhci_host * host,u32 intmask)1392bb6e3581SBOUGH CHEN static u32 esdhc_cqhci_irq(struct sdhci_host *host, u32 intmask)
1393bb6e3581SBOUGH CHEN {
1394bb6e3581SBOUGH CHEN 	int cmd_error = 0;
1395bb6e3581SBOUGH CHEN 	int data_error = 0;
1396bb6e3581SBOUGH CHEN 
1397bb6e3581SBOUGH CHEN 	if (!sdhci_cqe_irq(host, intmask, &cmd_error, &data_error))
1398bb6e3581SBOUGH CHEN 		return intmask;
1399bb6e3581SBOUGH CHEN 
1400bb6e3581SBOUGH CHEN 	cqhci_irq(host->mmc, intmask, cmd_error, data_error);
1401bb6e3581SBOUGH CHEN 
1402bb6e3581SBOUGH CHEN 	return 0;
1403bb6e3581SBOUGH CHEN }
1404bb6e3581SBOUGH CHEN 
14056e9fd28eSDong Aisheng static struct sdhci_ops sdhci_esdhc_ops = {
1406e149860dSRichard Zhu 	.read_l = esdhc_readl_le,
14070c6d49ceSWolfram Sang 	.read_w = esdhc_readw_le,
140877da3da0SAaron Brice 	.read_b = esdhc_readb_le,
1409e149860dSRichard Zhu 	.write_l = esdhc_writel_le,
14100c6d49ceSWolfram Sang 	.write_w = esdhc_writew_le,
14110c6d49ceSWolfram Sang 	.write_b = esdhc_writeb_le,
14128ba9580aSLucas Stach 	.set_clock = esdhc_pltfm_set_clock,
14130ddf03c9SLucas Stach 	.get_max_clock = esdhc_pltfm_get_max_clock,
14140c6d49ceSWolfram Sang 	.get_min_clock = esdhc_pltfm_get_min_clock,
141510fd0ad9SAisheng Dong 	.get_max_timeout_count = esdhc_get_max_timeout_count,
1416913413c3SShawn Guo 	.get_ro = esdhc_pltfm_get_ro,
1417e33eb8e2SAisheng Dong 	.set_timeout = esdhc_set_timeout,
14182317f56cSRussell King 	.set_bus_width = esdhc_pltfm_set_bus_width,
1419ad93220dSDong Aisheng 	.set_uhs_signaling = esdhc_set_uhs_signaling,
14200718e59aSRussell King 	.reset = esdhc_reset,
1421bb6e3581SBOUGH CHEN 	.irq = esdhc_cqhci_irq,
14223722c74cSHaibo Chen 	.dump_vendor_regs = esdhc_dump_debug_regs,
14230c6d49ceSWolfram Sang };
14240c6d49ceSWolfram Sang 
14251db5eebfSLars-Peter Clausen static const struct sdhci_pltfm_data sdhci_esdhc_imx_pdata = {
142697e4ba6aSRichard Zhu 	.quirks = ESDHC_DEFAULT_QUIRKS | SDHCI_QUIRK_NO_HISPD_BIT
142797e4ba6aSRichard Zhu 			| SDHCI_QUIRK_NO_ENDATTR_IN_NOPDESC
142897e4ba6aSRichard Zhu 			| SDHCI_QUIRK_BROKEN_ADMA_ZEROLEN_DESC
142985d6509dSShawn Guo 			| SDHCI_QUIRK_BROKEN_CARD_DETECTION,
143085d6509dSShawn Guo 	.ops = &sdhci_esdhc_ops,
143185d6509dSShawn Guo };
143285d6509dSShawn Guo 
sdhci_esdhc_imx_hwinit(struct sdhci_host * host)1433f3f5cf3dSDong Aisheng static void sdhci_esdhc_imx_hwinit(struct sdhci_host *host)
1434f3f5cf3dSDong Aisheng {
1435f3f5cf3dSDong Aisheng 	struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
1436f3f5cf3dSDong Aisheng 	struct pltfm_imx_data *imx_data = sdhci_pltfm_priv(pltfm_host);
1437982cf37dSHaibo Chen 	struct cqhci_host *cq_host = host->mmc->cqe_private;
14381e336aa0SHaibo Chen 	u32 tmp;
1439f3f5cf3dSDong Aisheng 
1440f3f5cf3dSDong Aisheng 	if (esdhc_is_usdhc(imx_data)) {
1441f3f5cf3dSDong Aisheng 		/*
1442f3f5cf3dSDong Aisheng 		 * The imx6q ROM code will change the default watermark
1443f3f5cf3dSDong Aisheng 		 * level setting to something insane.  Change it back here.
1444f3f5cf3dSDong Aisheng 		 */
1445f3f5cf3dSDong Aisheng 		writel(ESDHC_WTMK_DEFAULT_VAL, host->ioaddr + ESDHC_WTMK_LVL);
1446f3f5cf3dSDong Aisheng 
1447f3f5cf3dSDong Aisheng 		/*
1448f3f5cf3dSDong Aisheng 		 * ROM code will change the bit burst_length_enable setting
1449d04f8d5bSBenoît Thébaudeau 		 * to zero if this usdhc is chosen to boot system. Change
1450f3f5cf3dSDong Aisheng 		 * it back here, otherwise it will impact the performance a
1451f3f5cf3dSDong Aisheng 		 * lot. This bit is used to enable/disable the burst length
1452d04f8d5bSBenoît Thébaudeau 		 * for the external AHB2AXI bridge. It's useful especially
1453f3f5cf3dSDong Aisheng 		 * for INCR transfer because without burst length indicator,
1454f3f5cf3dSDong Aisheng 		 * the AHB2AXI bridge does not know the burst length in
1455f3f5cf3dSDong Aisheng 		 * advance. And without burst length indicator, AHB INCR
1456f3f5cf3dSDong Aisheng 		 * transfer can only be converted to singles on the AXI side.
1457f3f5cf3dSDong Aisheng 		 */
1458f3f5cf3dSDong Aisheng 		writel(readl(host->ioaddr + SDHCI_HOST_CONTROL)
1459f3f5cf3dSDong Aisheng 			| ESDHC_BURST_LEN_EN_INCR,
1460f3f5cf3dSDong Aisheng 			host->ioaddr + SDHCI_HOST_CONTROL);
1461e30be063SBOUGH CHEN 
1462f3f5cf3dSDong Aisheng 		/*
1463d04f8d5bSBenoît Thébaudeau 		 * erratum ESDHC_FLAG_ERR004536 fix for MX6Q TO1.2 and MX6DL
1464f3f5cf3dSDong Aisheng 		 * TO1.1, it's harmless for MX6SL
1465f3f5cf3dSDong Aisheng 		 */
14665c4f0062SChester Lin 		if (!(imx_data->socdata->flags & ESDHC_FLAG_SKIP_ERR004536)) {
1467e30be063SBOUGH CHEN 			writel(readl(host->ioaddr + 0x6c) & ~BIT(7),
1468f3f5cf3dSDong Aisheng 				host->ioaddr + 0x6c);
14695c4f0062SChester Lin 		}
1470f3f5cf3dSDong Aisheng 
1471f3f5cf3dSDong Aisheng 		/* disable DLL_CTRL delay line settings */
1472f3f5cf3dSDong Aisheng 		writel(0x0, host->ioaddr + ESDHC_DLL_CTRL);
14732b16cf32SDong Aisheng 
1474bcdb5301SBOUGH CHEN 		/*
1475bcdb5301SBOUGH CHEN 		 * For the case of command with busy, if set the bit
1476bcdb5301SBOUGH CHEN 		 * ESDHC_VEND_SPEC2_EN_BUSY_IRQ, USDHC will generate a
1477bcdb5301SBOUGH CHEN 		 * transfer complete interrupt when busy is deasserted.
1478bcdb5301SBOUGH CHEN 		 * When CQHCI use DCMD to send a CMD need R1b respons,
1479bcdb5301SBOUGH CHEN 		 * CQHCI require to set ESDHC_VEND_SPEC2_EN_BUSY_IRQ,
1480bcdb5301SBOUGH CHEN 		 * otherwise DCMD will always meet timeout waiting for
1481bcdb5301SBOUGH CHEN 		 * hardware interrupt issue.
1482bcdb5301SBOUGH CHEN 		 */
1483bcdb5301SBOUGH CHEN 		if (imx_data->socdata->flags & ESDHC_FLAG_CQHCI) {
1484bcdb5301SBOUGH CHEN 			tmp = readl(host->ioaddr + ESDHC_VEND_SPEC2);
1485bcdb5301SBOUGH CHEN 			tmp |= ESDHC_VEND_SPEC2_EN_BUSY_IRQ;
1486bcdb5301SBOUGH CHEN 			writel(tmp, host->ioaddr + ESDHC_VEND_SPEC2);
1487bcdb5301SBOUGH CHEN 
1488bcdb5301SBOUGH CHEN 			host->quirks &= ~SDHCI_QUIRK_NO_BUSY_IRQ;
1489bcdb5301SBOUGH CHEN 		}
1490bcdb5301SBOUGH CHEN 
14912b16cf32SDong Aisheng 		if (imx_data->socdata->flags & ESDHC_FLAG_STD_TUNING) {
14922b16cf32SDong Aisheng 			tmp = readl(host->ioaddr + ESDHC_TUNING_CTRL);
14931e336aa0SHaibo Chen 			tmp |= ESDHC_STD_TUNING_EN;
14941e336aa0SHaibo Chen 
14951e336aa0SHaibo Chen 			/*
14961e336aa0SHaibo Chen 			 * ROM code or bootloader may config the start tap
14971e336aa0SHaibo Chen 			 * and step, unmask them first.
14981e336aa0SHaibo Chen 			 */
14991e336aa0SHaibo Chen 			tmp &= ~(ESDHC_TUNING_START_TAP_MASK | ESDHC_TUNING_STEP_MASK);
15001e336aa0SHaibo Chen 			if (imx_data->boarddata.tuning_start_tap)
15012b16cf32SDong Aisheng 				tmp |= imx_data->boarddata.tuning_start_tap;
15021e336aa0SHaibo Chen 			else
15031e336aa0SHaibo Chen 				tmp |= ESDHC_TUNING_START_TAP_DEFAULT;
15042b16cf32SDong Aisheng 
15052b16cf32SDong Aisheng 			if (imx_data->boarddata.tuning_step) {
15062b16cf32SDong Aisheng 				tmp |= imx_data->boarddata.tuning_step
15072b16cf32SDong Aisheng 					<< ESDHC_TUNING_STEP_SHIFT;
15081e336aa0SHaibo Chen 			} else {
15091e336aa0SHaibo Chen 				tmp |= ESDHC_TUNING_STEP_DEFAULT
15101e336aa0SHaibo Chen 					<< ESDHC_TUNING_STEP_SHIFT;
15112b16cf32SDong Aisheng 			}
151216e40e5bSHaibo Chen 
151316e40e5bSHaibo Chen 			/* Disable the CMD CRC check for tuning, if not, need to
151416e40e5bSHaibo Chen 			 * add some delay after every tuning command, because
151516e40e5bSHaibo Chen 			 * hardware standard tuning logic will directly go to next
151616e40e5bSHaibo Chen 			 * step once it detect the CMD CRC error, will not wait for
151716e40e5bSHaibo Chen 			 * the card side to finally send out the tuning data, trigger
151816e40e5bSHaibo Chen 			 * the buffer read ready interrupt immediately. If usdhc send
151916e40e5bSHaibo Chen 			 * the next tuning command some eMMC card will stuck, can't
152016e40e5bSHaibo Chen 			 * response, block the tuning procedure or the first command
152116e40e5bSHaibo Chen 			 * after the whole tuning procedure always can't get any response.
152216e40e5bSHaibo Chen 			 */
152316e40e5bSHaibo Chen 			tmp |= ESDHC_TUNING_CMD_CRC_CHECK_DISABLE;
15242b16cf32SDong Aisheng 			writel(tmp, host->ioaddr + ESDHC_TUNING_CTRL);
1525a98c557eSBOUGH CHEN 		} else if (imx_data->socdata->flags & ESDHC_FLAG_MAN_TUNING) {
1526a98c557eSBOUGH CHEN 			/*
1527a98c557eSBOUGH CHEN 			 * ESDHC_STD_TUNING_EN may be configed in bootloader
1528a98c557eSBOUGH CHEN 			 * or ROM code, so clear this bit here to make sure
1529a98c557eSBOUGH CHEN 			 * the manual tuning can work.
1530a98c557eSBOUGH CHEN 			 */
1531a98c557eSBOUGH CHEN 			tmp = readl(host->ioaddr + ESDHC_TUNING_CTRL);
1532a98c557eSBOUGH CHEN 			tmp &= ~ESDHC_STD_TUNING_EN;
1533a98c557eSBOUGH CHEN 			writel(tmp, host->ioaddr + ESDHC_TUNING_CTRL);
15342b16cf32SDong Aisheng 		}
1535982cf37dSHaibo Chen 
1536982cf37dSHaibo Chen 		/*
1537982cf37dSHaibo Chen 		 * On i.MX8MM, we are running Dual Linux OS, with 1st Linux using SD Card
15381ad0dcb9Swangjianli 		 * as rootfs storage, 2nd Linux using eMMC as rootfs storage. We let
1539982cf37dSHaibo Chen 		 * the 1st linux configure power/clock for the 2nd Linux.
1540982cf37dSHaibo Chen 		 *
1541982cf37dSHaibo Chen 		 * When the 2nd Linux is booting into rootfs stage, we let the 1st Linux
1542982cf37dSHaibo Chen 		 * to destroy the 2nd linux, then restart the 2nd linux, we met SDHCI dump.
1543982cf37dSHaibo Chen 		 * After we clear the pending interrupt and halt CQCTL, issue gone.
1544982cf37dSHaibo Chen 		 */
1545982cf37dSHaibo Chen 		if (cq_host) {
1546982cf37dSHaibo Chen 			tmp = cqhci_readl(cq_host, CQHCI_IS);
1547982cf37dSHaibo Chen 			cqhci_writel(cq_host, tmp, CQHCI_IS);
1548982cf37dSHaibo Chen 			cqhci_writel(cq_host, CQHCI_HALT, CQHCI_CTL);
1549982cf37dSHaibo Chen 		}
1550f3f5cf3dSDong Aisheng 	}
1551f3f5cf3dSDong Aisheng }
1552f3f5cf3dSDong Aisheng 
esdhc_cqe_enable(struct mmc_host * mmc)1553bb6e3581SBOUGH CHEN static void esdhc_cqe_enable(struct mmc_host *mmc)
1554bb6e3581SBOUGH CHEN {
1555bb6e3581SBOUGH CHEN 	struct sdhci_host *host = mmc_priv(mmc);
155685236d2bSBOUGH CHEN 	struct cqhci_host *cq_host = mmc->cqe_private;
1557bb6e3581SBOUGH CHEN 	u32 reg;
1558bb6e3581SBOUGH CHEN 	u16 mode;
1559bb6e3581SBOUGH CHEN 	int count = 10;
1560bb6e3581SBOUGH CHEN 
1561bb6e3581SBOUGH CHEN 	/*
1562bb6e3581SBOUGH CHEN 	 * CQE gets stuck if it sees Buffer Read Enable bit set, which can be
1563bb6e3581SBOUGH CHEN 	 * the case after tuning, so ensure the buffer is drained.
1564bb6e3581SBOUGH CHEN 	 */
1565bb6e3581SBOUGH CHEN 	reg = sdhci_readl(host, SDHCI_PRESENT_STATE);
1566bb6e3581SBOUGH CHEN 	while (reg & SDHCI_DATA_AVAILABLE) {
1567bb6e3581SBOUGH CHEN 		sdhci_readl(host, SDHCI_BUFFER);
1568bb6e3581SBOUGH CHEN 		reg = sdhci_readl(host, SDHCI_PRESENT_STATE);
1569bb6e3581SBOUGH CHEN 		if (count-- == 0) {
1570bb6e3581SBOUGH CHEN 			dev_warn(mmc_dev(host->mmc),
1571bb6e3581SBOUGH CHEN 				"CQE may get stuck because the Buffer Read Enable bit is set\n");
1572bb6e3581SBOUGH CHEN 			break;
1573bb6e3581SBOUGH CHEN 		}
1574bb6e3581SBOUGH CHEN 		mdelay(1);
1575bb6e3581SBOUGH CHEN 	}
1576bb6e3581SBOUGH CHEN 
1577bb6e3581SBOUGH CHEN 	/*
1578bb6e3581SBOUGH CHEN 	 * Runtime resume will reset the entire host controller, which
1579bb6e3581SBOUGH CHEN 	 * will also clear the DMAEN/BCEN of register ESDHC_MIX_CTRL.
1580bb6e3581SBOUGH CHEN 	 * Here set DMAEN and BCEN when enable CMDQ.
1581bb6e3581SBOUGH CHEN 	 */
1582bb6e3581SBOUGH CHEN 	mode = sdhci_readw(host, SDHCI_TRANSFER_MODE);
1583bb6e3581SBOUGH CHEN 	if (host->flags & SDHCI_REQ_USE_DMA)
1584bb6e3581SBOUGH CHEN 		mode |= SDHCI_TRNS_DMA;
1585bb6e3581SBOUGH CHEN 	if (!(host->quirks2 & SDHCI_QUIRK2_SUPPORT_SINGLE))
1586bb6e3581SBOUGH CHEN 		mode |= SDHCI_TRNS_BLK_CNT_EN;
1587bb6e3581SBOUGH CHEN 	sdhci_writew(host, mode, SDHCI_TRANSFER_MODE);
1588bb6e3581SBOUGH CHEN 
158985236d2bSBOUGH CHEN 	/*
159085236d2bSBOUGH CHEN 	 * Though Runtime resume reset the entire host controller,
159185236d2bSBOUGH CHEN 	 * but do not impact the CQHCI side, need to clear the
159285236d2bSBOUGH CHEN 	 * HALT bit, avoid CQHCI stuck in the first request when
159385236d2bSBOUGH CHEN 	 * system resume back.
159485236d2bSBOUGH CHEN 	 */
159585236d2bSBOUGH CHEN 	cqhci_writel(cq_host, 0, CQHCI_CTL);
1596a3cab1d2SSebastian Falbesoner 	if (cqhci_readl(cq_host, CQHCI_CTL) & CQHCI_HALT)
159785236d2bSBOUGH CHEN 		dev_err(mmc_dev(host->mmc),
159885236d2bSBOUGH CHEN 			"failed to exit halt state when enable CQE\n");
159985236d2bSBOUGH CHEN 
160085236d2bSBOUGH CHEN 
1601bb6e3581SBOUGH CHEN 	sdhci_cqe_enable(mmc);
1602bb6e3581SBOUGH CHEN }
1603bb6e3581SBOUGH CHEN 
esdhc_sdhci_dumpregs(struct mmc_host * mmc)1604bb6e3581SBOUGH CHEN static void esdhc_sdhci_dumpregs(struct mmc_host *mmc)
1605bb6e3581SBOUGH CHEN {
1606bb6e3581SBOUGH CHEN 	sdhci_dumpregs(mmc_priv(mmc));
1607bb6e3581SBOUGH CHEN }
1608bb6e3581SBOUGH CHEN 
1609bb6e3581SBOUGH CHEN static const struct cqhci_host_ops esdhc_cqhci_ops = {
1610bb6e3581SBOUGH CHEN 	.enable		= esdhc_cqe_enable,
1611bb6e3581SBOUGH CHEN 	.disable	= sdhci_cqe_disable,
1612bb6e3581SBOUGH CHEN 	.dumpregs	= esdhc_sdhci_dumpregs,
1613bb6e3581SBOUGH CHEN };
1614bb6e3581SBOUGH CHEN 
1615c3be1efdSBill Pemberton static int
sdhci_esdhc_imx_probe_dt(struct platform_device * pdev,struct sdhci_host * host,struct pltfm_imx_data * imx_data)1616abfafc2dSShawn Guo sdhci_esdhc_imx_probe_dt(struct platform_device *pdev,
161707bf2b54SSascha Hauer 			 struct sdhci_host *host,
161891fa4252SDong Aisheng 			 struct pltfm_imx_data *imx_data)
1619abfafc2dSShawn Guo {
1620abfafc2dSShawn Guo 	struct device_node *np = pdev->dev.of_node;
162191fa4252SDong Aisheng 	struct esdhc_platform_data *boarddata = &imx_data->boarddata;
16224800e87aSDong Aisheng 	int ret;
1623abfafc2dSShawn Guo 
1624ca6b5fe2SRob Herring 	if (of_property_read_bool(np, "fsl,wp-controller"))
1625abfafc2dSShawn Guo 		boarddata->wp_type = ESDHC_WP_CONTROLLER;
1626abfafc2dSShawn Guo 
162774ff81e1SLinus Walleij 	/*
162874ff81e1SLinus Walleij 	 * If we have this property, then activate WP check.
162974ff81e1SLinus Walleij 	 * Retrieveing and requesting the actual WP GPIO will happen
163074ff81e1SLinus Walleij 	 * in the call to mmc_of_parse().
163174ff81e1SLinus Walleij 	 */
163274ff81e1SLinus Walleij 	if (of_property_read_bool(np, "wp-gpios"))
1633abfafc2dSShawn Guo 		boarddata->wp_type = ESDHC_WP_GPIO;
1634abfafc2dSShawn Guo 
1635d407e30bSHaibo Chen 	of_property_read_u32(np, "fsl,tuning-step", &boarddata->tuning_step);
1636d87fc966SDong Aisheng 	of_property_read_u32(np, "fsl,tuning-start-tap",
1637d87fc966SDong Aisheng 			     &boarddata->tuning_start_tap);
1638d407e30bSHaibo Chen 
16395bd2acdcSHaibo Chen 	of_property_read_u32(np, "fsl,strobe-dll-delay-target",
16405bd2acdcSHaibo Chen 				&boarddata->strobe_dll_delay_target);
1641ca6b5fe2SRob Herring 	if (of_property_read_bool(np, "no-1-8-v"))
164286f495c5SStefan Agner 		host->quirks2 |= SDHCI_QUIRK2_NO_1_8_V;
1643ad93220dSDong Aisheng 
1644602519b2SDong Aisheng 	if (of_property_read_u32(np, "fsl,delay-line", &boarddata->delay_line))
1645602519b2SDong Aisheng 		boarddata->delay_line = 0;
1646602519b2SDong Aisheng 
16476dab809bSAndy Shevchenko 	mmc_of_parse_voltage(host->mmc, &host->ocr_mask);
164807bf2b54SSascha Hauer 
1649f410ee0aSPeng Fan 	if (esdhc_is_usdhc(imx_data) && !IS_ERR(imx_data->pinctrl)) {
165091fa4252SDong Aisheng 		imx_data->pins_100mhz = pinctrl_lookup_state(imx_data->pinctrl,
165191fa4252SDong Aisheng 						ESDHC_PINCTRL_STATE_100MHZ);
165291fa4252SDong Aisheng 		imx_data->pins_200mhz = pinctrl_lookup_state(imx_data->pinctrl,
165391fa4252SDong Aisheng 						ESDHC_PINCTRL_STATE_200MHZ);
165491fa4252SDong Aisheng 	}
165591fa4252SDong Aisheng 
165615064119SFabio Estevam 	/* call to generic mmc_of_parse to support additional capabilities */
16574800e87aSDong Aisheng 	ret = mmc_of_parse(host->mmc);
16584800e87aSDong Aisheng 	if (ret)
16594800e87aSDong Aisheng 		return ret;
16604800e87aSDong Aisheng 
166181dce149SHaibo Chen 	/* HS400/HS400ES require 8 bit bus */
166281dce149SHaibo Chen 	if (!(host->mmc->caps & MMC_CAP_8_BIT_DATA))
166381dce149SHaibo Chen 		host->mmc->caps2 &= ~(MMC_CAP2_HS400 | MMC_CAP2_HS400_ES);
166481dce149SHaibo Chen 
1665287980e4SArnd Bergmann 	if (mmc_gpio_get_cd(host->mmc) >= 0)
16664800e87aSDong Aisheng 		host->quirks &= ~SDHCI_QUIRK_BROKEN_CARD_DETECTION;
16674800e87aSDong Aisheng 
16684800e87aSDong Aisheng 	return 0;
1669abfafc2dSShawn Guo }
1670abfafc2dSShawn Guo 
sdhci_esdhc_imx_probe(struct platform_device * pdev)1671c3be1efdSBill Pemberton static int sdhci_esdhc_imx_probe(struct platform_device *pdev)
167295f25efeSWolfram Sang {
167385d6509dSShawn Guo 	struct sdhci_pltfm_host *pltfm_host;
167485d6509dSShawn Guo 	struct sdhci_host *host;
1675bb6e3581SBOUGH CHEN 	struct cqhci_host *cq_host;
16760c6d49ceSWolfram Sang 	int err;
1677e149860dSRichard Zhu 	struct pltfm_imx_data *imx_data;
167895f25efeSWolfram Sang 
1679070e6d3fSJisheng Zhang 	host = sdhci_pltfm_init(pdev, &sdhci_esdhc_imx_pdata,
1680070e6d3fSJisheng Zhang 				sizeof(*imx_data));
168185d6509dSShawn Guo 	if (IS_ERR(host))
168285d6509dSShawn Guo 		return PTR_ERR(host);
168385d6509dSShawn Guo 
168485d6509dSShawn Guo 	pltfm_host = sdhci_priv(host);
168585d6509dSShawn Guo 
1686070e6d3fSJisheng Zhang 	imx_data = sdhci_pltfm_priv(pltfm_host);
168757ed3314SShawn Guo 
168891b3d2e5SFabio Estevam 	imx_data->socdata = device_get_match_data(&pdev->dev);
168985d6509dSShawn Guo 
16901c4989b0SBOUGH CHEN 	if (imx_data->socdata->flags & ESDHC_FLAG_PMQOS)
1691d1b98305SRafael J. Wysocki 		cpu_latency_qos_add_request(&imx_data->pm_qos_req, 0);
16921c4989b0SBOUGH CHEN 
169352dac615SSascha Hauer 	imx_data->clk_ipg = devm_clk_get(&pdev->dev, "ipg");
169452dac615SSascha Hauer 	if (IS_ERR(imx_data->clk_ipg)) {
169552dac615SSascha Hauer 		err = PTR_ERR(imx_data->clk_ipg);
1696e3af31c6SShawn Guo 		goto free_sdhci;
169795f25efeSWolfram Sang 	}
169852dac615SSascha Hauer 
169952dac615SSascha Hauer 	imx_data->clk_ahb = devm_clk_get(&pdev->dev, "ahb");
170052dac615SSascha Hauer 	if (IS_ERR(imx_data->clk_ahb)) {
170152dac615SSascha Hauer 		err = PTR_ERR(imx_data->clk_ahb);
1702e3af31c6SShawn Guo 		goto free_sdhci;
170352dac615SSascha Hauer 	}
170452dac615SSascha Hauer 
170552dac615SSascha Hauer 	imx_data->clk_per = devm_clk_get(&pdev->dev, "per");
170652dac615SSascha Hauer 	if (IS_ERR(imx_data->clk_per)) {
170752dac615SSascha Hauer 		err = PTR_ERR(imx_data->clk_per);
1708e3af31c6SShawn Guo 		goto free_sdhci;
170952dac615SSascha Hauer 	}
171052dac615SSascha Hauer 
171152dac615SSascha Hauer 	pltfm_host->clk = imx_data->clk_per;
171217b1eb7fSFabio Estevam 	err = clk_prepare_enable(imx_data->clk_per);
171317b1eb7fSFabio Estevam 	if (err)
171417b1eb7fSFabio Estevam 		goto free_sdhci;
171517b1eb7fSFabio Estevam 	err = clk_prepare_enable(imx_data->clk_ipg);
171617b1eb7fSFabio Estevam 	if (err)
171717b1eb7fSFabio Estevam 		goto disable_per_clk;
171817b1eb7fSFabio Estevam 	err = clk_prepare_enable(imx_data->clk_ahb);
171917b1eb7fSFabio Estevam 	if (err)
172017b1eb7fSFabio Estevam 		goto disable_ipg_clk;
172195f25efeSWolfram Sang 
1722*63e555d9SCiprian Costea 	pltfm_host->clock = clk_get_rate(pltfm_host->clk);
1723*63e555d9SCiprian Costea 	if (!pltfm_host->clock) {
1724*63e555d9SCiprian Costea 		dev_err(mmc_dev(host->mmc), "could not get clk rate\n");
1725*63e555d9SCiprian Costea 		err = -EINVAL;
1726*63e555d9SCiprian Costea 		goto disable_ahb_clk;
1727*63e555d9SCiprian Costea 	}
1728*63e555d9SCiprian Costea 
1729ad93220dSDong Aisheng 	imx_data->pinctrl = devm_pinctrl_get(&pdev->dev);
17309e70ff99SHaibo Chen 	if (IS_ERR(imx_data->pinctrl))
1731b62eee9fSHaibo Chen 		dev_warn(mmc_dev(host->mmc), "could not get pinctrl\n");
1732e62d8b8fSDong Aisheng 
173369ed60e0SDong Aisheng 	if (esdhc_is_usdhc(imx_data)) {
173469ed60e0SDong Aisheng 		host->quirks2 |= SDHCI_QUIRK2_PRESET_VALUE_BROKEN;
173509c8192bSStefan Agner 		host->mmc->caps |= MMC_CAP_1_8V_DDR | MMC_CAP_3_3V_DDR;
1736f6140462SHaibo Chen 
1737f6140462SHaibo Chen 		/* GPIO CD can be set as a wakeup source */
1738a52b67bdSCiprian Costea 		if (!(imx_data->socdata->flags & ESDHC_FLAG_SKIP_CD_WAKE))
1739f6140462SHaibo Chen 			host->mmc->caps |= MMC_CAP_CD_WAKE;
1740f6140462SHaibo Chen 
17414245afffSDong Aisheng 		if (!(imx_data->socdata->flags & ESDHC_FLAG_HS200))
17424245afffSDong Aisheng 			host->quirks2 |= SDHCI_QUIRK2_BROKEN_HS200;
1743a75dcbf4SDong Aisheng 
1744a75dcbf4SDong Aisheng 		/* clear tuning bits in case ROM has set it already */
1745a75dcbf4SDong Aisheng 		writel(0x0, host->ioaddr + ESDHC_MIX_CTRL);
1746869f8a69SAdrian Hunter 		writel(0x0, host->ioaddr + SDHCI_AUTO_CMD_STATUS);
1747a75dcbf4SDong Aisheng 		writel(0x0, host->ioaddr + ESDHC_TUNE_CTRL_STATUS);
1748de3e1dd0SBOUGH CHEN 
1749de3e1dd0SBOUGH CHEN 		/*
1750de3e1dd0SBOUGH CHEN 		 * Link usdhc specific mmc_host_ops execute_tuning function,
1751de3e1dd0SBOUGH CHEN 		 * to replace the standard one in sdhci_ops.
1752de3e1dd0SBOUGH CHEN 		 */
1753de3e1dd0SBOUGH CHEN 		host->mmc_host_ops.execute_tuning = usdhc_execute_tuning;
175452e4c32bSHaibo Chen 
175552e4c32bSHaibo Chen 		/*
175652e4c32bSHaibo Chen 		 * Link usdhc specific mmc_host_ops init card function,
175752e4c32bSHaibo Chen 		 * to distinguish the card type.
175852e4c32bSHaibo Chen 		 */
175952e4c32bSHaibo Chen 		host->mmc_host_ops.init_card = usdhc_init_card;
176069ed60e0SDong Aisheng 	}
1761f750ba9bSShawn Guo 
17626e9fd28eSDong Aisheng 	if (imx_data->socdata->flags & ESDHC_FLAG_MAN_TUNING)
17636e9fd28eSDong Aisheng 		sdhci_esdhc_ops.platform_execute_tuning =
17646e9fd28eSDong Aisheng 					esdhc_executing_tuning;
17658b2bb0adSDong Aisheng 
176618094430SDong Aisheng 	if (imx_data->socdata->flags & ESDHC_FLAG_ERR004536)
176718094430SDong Aisheng 		host->quirks |= SDHCI_QUIRK_BROKEN_ADMA;
176818094430SDong Aisheng 
176981dce149SHaibo Chen 	if (imx_data->socdata->flags & ESDHC_FLAG_HS400)
17702991ad76SLucas Stach 		host->mmc->caps2 |= MMC_CAP2_HS400;
177128b07674SHaibo Chen 
177274898cbcSHaibo Chen 	if (imx_data->socdata->flags & ESDHC_FLAG_BROKEN_AUTO_CMD23)
177374898cbcSHaibo Chen 		host->quirks2 |= SDHCI_QUIRK2_ACMD23_BROKEN;
177474898cbcSHaibo Chen 
177581dce149SHaibo Chen 	if (imx_data->socdata->flags & ESDHC_FLAG_HS400_ES) {
1776029e2476SBOUGH CHEN 		host->mmc->caps2 |= MMC_CAP2_HS400_ES;
1777029e2476SBOUGH CHEN 		host->mmc_host_ops.hs400_enhanced_strobe =
1778029e2476SBOUGH CHEN 					esdhc_hs400_enhanced_strobe;
1779029e2476SBOUGH CHEN 	}
1780029e2476SBOUGH CHEN 
1781bb6e3581SBOUGH CHEN 	if (imx_data->socdata->flags & ESDHC_FLAG_CQHCI) {
1782bcdb5301SBOUGH CHEN 		host->mmc->caps2 |= MMC_CAP2_CQE | MMC_CAP2_CQE_DCMD;
1783bb6e3581SBOUGH CHEN 		cq_host = devm_kzalloc(&pdev->dev, sizeof(*cq_host), GFP_KERNEL);
17849a633f3bSWei Yongjun 		if (!cq_host) {
17859a633f3bSWei Yongjun 			err = -ENOMEM;
1786bb6e3581SBOUGH CHEN 			goto disable_ahb_clk;
1787bb6e3581SBOUGH CHEN 		}
1788bb6e3581SBOUGH CHEN 
1789bb6e3581SBOUGH CHEN 		cq_host->mmio = host->ioaddr + ESDHC_CQHCI_ADDR_OFFSET;
1790bb6e3581SBOUGH CHEN 		cq_host->ops = &esdhc_cqhci_ops;
1791bb6e3581SBOUGH CHEN 
1792bb6e3581SBOUGH CHEN 		err = cqhci_init(cq_host, host->mmc, false);
1793bb6e3581SBOUGH CHEN 		if (err)
1794bb6e3581SBOUGH CHEN 			goto disable_ahb_clk;
1795bb6e3581SBOUGH CHEN 	}
1796bb6e3581SBOUGH CHEN 
179781dce149SHaibo Chen 	err = sdhci_esdhc_imx_probe_dt(pdev, host, imx_data);
179881dce149SHaibo Chen 	if (err)
179981dce149SHaibo Chen 		goto disable_ahb_clk;
180081dce149SHaibo Chen 
1801f3f5cf3dSDong Aisheng 	sdhci_esdhc_imx_hwinit(host);
1802f3f5cf3dSDong Aisheng 
180385d6509dSShawn Guo 	err = sdhci_add_host(host);
180485d6509dSShawn Guo 	if (err)
180517b1eb7fSFabio Estevam 		goto disable_ahb_clk;
180685d6509dSShawn Guo 
1807f62f7bccSHaibo Chen 	/*
1808f62f7bccSHaibo Chen 	 * Setup the wakeup capability here, let user to decide
1809f62f7bccSHaibo Chen 	 * whether need to enable this wakeup through sysfs interface.
1810f62f7bccSHaibo Chen 	 */
1811f62f7bccSHaibo Chen 	if ((host->mmc->pm_caps & MMC_PM_KEEP_POWER) &&
1812f62f7bccSHaibo Chen 			(host->mmc->pm_caps & MMC_PM_WAKE_SDIO_IRQ))
1813f62f7bccSHaibo Chen 		device_set_wakeup_capable(&pdev->dev, true);
1814f62f7bccSHaibo Chen 
181589d7e5c1SDong Aisheng 	pm_runtime_set_active(&pdev->dev);
181689d7e5c1SDong Aisheng 	pm_runtime_set_autosuspend_delay(&pdev->dev, 50);
181789d7e5c1SDong Aisheng 	pm_runtime_use_autosuspend(&pdev->dev);
181889d7e5c1SDong Aisheng 	pm_suspend_ignore_children(&pdev->dev, 1);
181977903c01SUlf Hansson 	pm_runtime_enable(&pdev->dev);
182089d7e5c1SDong Aisheng 
18217e29c306SWolfram Sang 	return 0;
18227e29c306SWolfram Sang 
182317b1eb7fSFabio Estevam disable_ahb_clk:
182452dac615SSascha Hauer 	clk_disable_unprepare(imx_data->clk_ahb);
182517b1eb7fSFabio Estevam disable_ipg_clk:
182617b1eb7fSFabio Estevam 	clk_disable_unprepare(imx_data->clk_ipg);
182717b1eb7fSFabio Estevam disable_per_clk:
182817b1eb7fSFabio Estevam 	clk_disable_unprepare(imx_data->clk_per);
1829e3af31c6SShawn Guo free_sdhci:
18301c4989b0SBOUGH CHEN 	if (imx_data->socdata->flags & ESDHC_FLAG_PMQOS)
1831d1b98305SRafael J. Wysocki 		cpu_latency_qos_remove_request(&imx_data->pm_qos_req);
183285d6509dSShawn Guo 	sdhci_pltfm_free(pdev);
183385d6509dSShawn Guo 	return err;
183495f25efeSWolfram Sang }
183595f25efeSWolfram Sang 
sdhci_esdhc_imx_remove(struct platform_device * pdev)183653b9222eSYangtao Li static void sdhci_esdhc_imx_remove(struct platform_device *pdev)
183795f25efeSWolfram Sang {
183885d6509dSShawn Guo 	struct sdhci_host *host = platform_get_drvdata(pdev);
183995f25efeSWolfram Sang 	struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
1840070e6d3fSJisheng Zhang 	struct pltfm_imx_data *imx_data = sdhci_pltfm_priv(pltfm_host);
1841a56f4413SFrank Li 	int dead;
184285d6509dSShawn Guo 
18430b414368SUlf Hansson 	pm_runtime_get_sync(&pdev->dev);
1844a56f4413SFrank Li 	dead = (readl(host->ioaddr + SDHCI_INT_STATUS) == 0xffffffff);
18450b414368SUlf Hansson 	pm_runtime_disable(&pdev->dev);
18460b414368SUlf Hansson 	pm_runtime_put_noidle(&pdev->dev);
18470b414368SUlf Hansson 
184885d6509dSShawn Guo 	sdhci_remove_host(host, dead);
18490c6d49ceSWolfram Sang 
185052dac615SSascha Hauer 	clk_disable_unprepare(imx_data->clk_per);
185152dac615SSascha Hauer 	clk_disable_unprepare(imx_data->clk_ipg);
185252dac615SSascha Hauer 	clk_disable_unprepare(imx_data->clk_ahb);
185352dac615SSascha Hauer 
18541c4989b0SBOUGH CHEN 	if (imx_data->socdata->flags & ESDHC_FLAG_PMQOS)
1855d1b98305SRafael J. Wysocki 		cpu_latency_qos_remove_request(&imx_data->pm_qos_req);
18561c4989b0SBOUGH CHEN 
185785d6509dSShawn Guo 	sdhci_pltfm_free(pdev);
185895f25efeSWolfram Sang }
185995f25efeSWolfram Sang 
18602788ed42SUlf Hansson #ifdef CONFIG_PM_SLEEP
sdhci_esdhc_suspend(struct device * dev)186104143fbaSDong Aisheng static int sdhci_esdhc_suspend(struct device *dev)
186204143fbaSDong Aisheng {
18633e3274abSUlf Hansson 	struct sdhci_host *host = dev_get_drvdata(dev);
1864a26a4f1bSHaibo Chen 	struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
1865a26a4f1bSHaibo Chen 	struct pltfm_imx_data *imx_data = sdhci_pltfm_priv(pltfm_host);
1866bb6e3581SBOUGH CHEN 	int ret;
1867bb6e3581SBOUGH CHEN 
1868bb6e3581SBOUGH CHEN 	if (host->mmc->caps2 & MMC_CAP2_CQE) {
1869bb6e3581SBOUGH CHEN 		ret = cqhci_suspend(host->mmc);
1870bb6e3581SBOUGH CHEN 		if (ret)
1871bb6e3581SBOUGH CHEN 			return ret;
1872bb6e3581SBOUGH CHEN 	}
18733e3274abSUlf Hansson 
1874a26a4f1bSHaibo Chen 	if ((imx_data->socdata->flags & ESDHC_FLAG_STATE_LOST_IN_LPMODE) &&
1875a26a4f1bSHaibo Chen 		(host->tuning_mode != SDHCI_TUNING_MODE_1)) {
1876a26a4f1bSHaibo Chen 		mmc_retune_timer_stop(host->mmc);
1877a26a4f1bSHaibo Chen 		mmc_retune_needed(host->mmc);
1878a26a4f1bSHaibo Chen 	}
1879a26a4f1bSHaibo Chen 
1880d38dcad4SAdrian Hunter 	if (host->tuning_mode != SDHCI_TUNING_MODE_3)
1881d38dcad4SAdrian Hunter 		mmc_retune_needed(host->mmc);
1882d38dcad4SAdrian Hunter 
1883af8fade4SHaibo Chen 	ret = sdhci_suspend_host(host);
1884f6140462SHaibo Chen 	if (ret)
1885f6140462SHaibo Chen 		return ret;
1886f6140462SHaibo Chen 
1887f6140462SHaibo Chen 	ret = pinctrl_pm_select_sleep_state(dev);
1888f6140462SHaibo Chen 	if (ret)
1889f6140462SHaibo Chen 		return ret;
1890f6140462SHaibo Chen 
1891f6140462SHaibo Chen 	ret = mmc_gpio_set_cd_wake(host->mmc, true);
1892af8fade4SHaibo Chen 
1893af8fade4SHaibo Chen 	return ret;
189404143fbaSDong Aisheng }
189504143fbaSDong Aisheng 
sdhci_esdhc_resume(struct device * dev)189604143fbaSDong Aisheng static int sdhci_esdhc_resume(struct device *dev)
189704143fbaSDong Aisheng {
1898cc17e129SDong Aisheng 	struct sdhci_host *host = dev_get_drvdata(dev);
1899bb6e3581SBOUGH CHEN 	int ret;
1900cc17e129SDong Aisheng 
1901af8fade4SHaibo Chen 	ret = pinctrl_pm_select_default_state(dev);
1902af8fade4SHaibo Chen 	if (ret)
1903af8fade4SHaibo Chen 		return ret;
1904af8fade4SHaibo Chen 
190519dbfdd3SDong Aisheng 	/* re-initialize hw state in case it's lost in low power mode */
190619dbfdd3SDong Aisheng 	sdhci_esdhc_imx_hwinit(host);
1907cc17e129SDong Aisheng 
1908bb6e3581SBOUGH CHEN 	ret = sdhci_resume_host(host);
1909bb6e3581SBOUGH CHEN 	if (ret)
1910bb6e3581SBOUGH CHEN 		return ret;
1911bb6e3581SBOUGH CHEN 
1912bb6e3581SBOUGH CHEN 	if (host->mmc->caps2 & MMC_CAP2_CQE)
1913bb6e3581SBOUGH CHEN 		ret = cqhci_resume(host->mmc);
1914bb6e3581SBOUGH CHEN 
1915f6140462SHaibo Chen 	if (!ret)
1916f6140462SHaibo Chen 		ret = mmc_gpio_set_cd_wake(host->mmc, false);
1917f6140462SHaibo Chen 
1918bb6e3581SBOUGH CHEN 	return ret;
191904143fbaSDong Aisheng }
19202788ed42SUlf Hansson #endif
192104143fbaSDong Aisheng 
19222788ed42SUlf Hansson #ifdef CONFIG_PM
sdhci_esdhc_runtime_suspend(struct device * dev)192389d7e5c1SDong Aisheng static int sdhci_esdhc_runtime_suspend(struct device *dev)
192489d7e5c1SDong Aisheng {
192589d7e5c1SDong Aisheng 	struct sdhci_host *host = dev_get_drvdata(dev);
192689d7e5c1SDong Aisheng 	struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
1927070e6d3fSJisheng Zhang 	struct pltfm_imx_data *imx_data = sdhci_pltfm_priv(pltfm_host);
192889d7e5c1SDong Aisheng 	int ret;
192989d7e5c1SDong Aisheng 
1930bb6e3581SBOUGH CHEN 	if (host->mmc->caps2 & MMC_CAP2_CQE) {
1931bb6e3581SBOUGH CHEN 		ret = cqhci_suspend(host->mmc);
1932bb6e3581SBOUGH CHEN 		if (ret)
1933bb6e3581SBOUGH CHEN 			return ret;
1934bb6e3581SBOUGH CHEN 	}
1935bb6e3581SBOUGH CHEN 
193689d7e5c1SDong Aisheng 	ret = sdhci_runtime_suspend_host(host);
1937371d39faSMichael Trimarchi 	if (ret)
1938371d39faSMichael Trimarchi 		return ret;
193989d7e5c1SDong Aisheng 
1940d38dcad4SAdrian Hunter 	if (host->tuning_mode != SDHCI_TUNING_MODE_3)
1941d38dcad4SAdrian Hunter 		mmc_retune_needed(host->mmc);
1942d38dcad4SAdrian Hunter 
19433602785bSMichael Trimarchi 	imx_data->actual_clock = host->mmc->actual_clock;
19443602785bSMichael Trimarchi 	esdhc_pltfm_set_clock(host, 0);
194589d7e5c1SDong Aisheng 	clk_disable_unprepare(imx_data->clk_per);
194689d7e5c1SDong Aisheng 	clk_disable_unprepare(imx_data->clk_ipg);
194789d7e5c1SDong Aisheng 	clk_disable_unprepare(imx_data->clk_ahb);
194889d7e5c1SDong Aisheng 
19491c4989b0SBOUGH CHEN 	if (imx_data->socdata->flags & ESDHC_FLAG_PMQOS)
1950d1b98305SRafael J. Wysocki 		cpu_latency_qos_remove_request(&imx_data->pm_qos_req);
19511c4989b0SBOUGH CHEN 
195289d7e5c1SDong Aisheng 	return ret;
195389d7e5c1SDong Aisheng }
195489d7e5c1SDong Aisheng 
sdhci_esdhc_runtime_resume(struct device * dev)195589d7e5c1SDong Aisheng static int sdhci_esdhc_runtime_resume(struct device *dev)
195689d7e5c1SDong Aisheng {
195789d7e5c1SDong Aisheng 	struct sdhci_host *host = dev_get_drvdata(dev);
195889d7e5c1SDong Aisheng 	struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
1959070e6d3fSJisheng Zhang 	struct pltfm_imx_data *imx_data = sdhci_pltfm_priv(pltfm_host);
196017b1eb7fSFabio Estevam 	int err;
196189d7e5c1SDong Aisheng 
19621c4989b0SBOUGH CHEN 	if (imx_data->socdata->flags & ESDHC_FLAG_PMQOS)
1963d1b98305SRafael J. Wysocki 		cpu_latency_qos_add_request(&imx_data->pm_qos_req, 0);
19641c4989b0SBOUGH CHEN 
19655c11f1ffSHaibo Chen 	if (imx_data->socdata->flags & ESDHC_FLAG_CLK_RATE_LOST_IN_PM_RUNTIME)
19665c11f1ffSHaibo Chen 		clk_set_rate(imx_data->clk_per, pltfm_host->clock);
19675c11f1ffSHaibo Chen 
1968a0ad3087SMichael Trimarchi 	err = clk_prepare_enable(imx_data->clk_ahb);
1969a0ad3087SMichael Trimarchi 	if (err)
19701c4989b0SBOUGH CHEN 		goto remove_pm_qos_request;
1971a0ad3087SMichael Trimarchi 
197217b1eb7fSFabio Estevam 	err = clk_prepare_enable(imx_data->clk_per);
197317b1eb7fSFabio Estevam 	if (err)
1974a0ad3087SMichael Trimarchi 		goto disable_ahb_clk;
1975af5d2b7bSUlf Hansson 
197617b1eb7fSFabio Estevam 	err = clk_prepare_enable(imx_data->clk_ipg);
197717b1eb7fSFabio Estevam 	if (err)
197817b1eb7fSFabio Estevam 		goto disable_per_clk;
1979af5d2b7bSUlf Hansson 
19803602785bSMichael Trimarchi 	esdhc_pltfm_set_clock(host, imx_data->actual_clock);
1981a0ad3087SMichael Trimarchi 
1982c6303c5dSBaolin Wang 	err = sdhci_runtime_resume_host(host, 0);
198317b1eb7fSFabio Estevam 	if (err)
1984a0ad3087SMichael Trimarchi 		goto disable_ipg_clk;
198589d7e5c1SDong Aisheng 
1986bb6e3581SBOUGH CHEN 	if (host->mmc->caps2 & MMC_CAP2_CQE)
1987bb6e3581SBOUGH CHEN 		err = cqhci_resume(host->mmc);
1988bb6e3581SBOUGH CHEN 
1989bb6e3581SBOUGH CHEN 	return err;
199017b1eb7fSFabio Estevam 
199117b1eb7fSFabio Estevam disable_ipg_clk:
199217b1eb7fSFabio Estevam 	clk_disable_unprepare(imx_data->clk_ipg);
199317b1eb7fSFabio Estevam disable_per_clk:
199417b1eb7fSFabio Estevam 	clk_disable_unprepare(imx_data->clk_per);
1995a0ad3087SMichael Trimarchi disable_ahb_clk:
1996a0ad3087SMichael Trimarchi 	clk_disable_unprepare(imx_data->clk_ahb);
19971c4989b0SBOUGH CHEN remove_pm_qos_request:
19981c4989b0SBOUGH CHEN 	if (imx_data->socdata->flags & ESDHC_FLAG_PMQOS)
1999d1b98305SRafael J. Wysocki 		cpu_latency_qos_remove_request(&imx_data->pm_qos_req);
200017b1eb7fSFabio Estevam 	return err;
200189d7e5c1SDong Aisheng }
200289d7e5c1SDong Aisheng #endif
200389d7e5c1SDong Aisheng 
200489d7e5c1SDong Aisheng static const struct dev_pm_ops sdhci_esdhc_pmops = {
200504143fbaSDong Aisheng 	SET_SYSTEM_SLEEP_PM_OPS(sdhci_esdhc_suspend, sdhci_esdhc_resume)
200689d7e5c1SDong Aisheng 	SET_RUNTIME_PM_OPS(sdhci_esdhc_runtime_suspend,
200789d7e5c1SDong Aisheng 				sdhci_esdhc_runtime_resume, NULL)
200889d7e5c1SDong Aisheng };
200989d7e5c1SDong Aisheng 
201085d6509dSShawn Guo static struct platform_driver sdhci_esdhc_imx_driver = {
201185d6509dSShawn Guo 	.driver		= {
201285d6509dSShawn Guo 		.name	= "sdhci-esdhc-imx",
201321b2cec6SDouglas Anderson 		.probe_type = PROBE_PREFER_ASYNCHRONOUS,
2014abfafc2dSShawn Guo 		.of_match_table = imx_esdhc_dt_ids,
201589d7e5c1SDong Aisheng 		.pm	= &sdhci_esdhc_pmops,
201685d6509dSShawn Guo 	},
201785d6509dSShawn Guo 	.probe		= sdhci_esdhc_imx_probe,
201853b9222eSYangtao Li 	.remove_new	= sdhci_esdhc_imx_remove,
201995f25efeSWolfram Sang };
202085d6509dSShawn Guo 
2021d1f81a64SAxel Lin module_platform_driver(sdhci_esdhc_imx_driver);
202285d6509dSShawn Guo 
202385d6509dSShawn Guo MODULE_DESCRIPTION("SDHCI driver for Freescale i.MX eSDHC");
2024035ff831SWolfram Sang MODULE_AUTHOR("Wolfram Sang <kernel@pengutronix.de>");
202585d6509dSShawn Guo MODULE_LICENSE("GPL v2");
2026