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> 25abfafc2dSShawn Guo #include <linux/of_device.h> 26e62d8b8fSDong Aisheng #include <linux/pinctrl/consumer.h> 2782906b13SArnd Bergmann #include <linux/platform_data/mmc-esdhc-imx.h> 2889d7e5c1SDong Aisheng #include <linux/pm_runtime.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) 98bcdb5301SBOUGH CHEN 996e9fd28eSDong Aisheng #define ESDHC_TUNING_CTRL 0xcc 1006e9fd28eSDong Aisheng #define ESDHC_STD_TUNING_EN (1 << 24) 1016e9fd28eSDong Aisheng /* NOTE: the minimum valid tuning start tap for mx6sl is 1 */ 102d87fc966SDong Aisheng #define ESDHC_TUNING_START_TAP_DEFAULT 0x1 1031194be8cSHaibo Chen #define ESDHC_TUNING_START_TAP_MASK 0x7f 10416e40e5bSHaibo Chen #define ESDHC_TUNING_CMD_CRC_CHECK_DISABLE (1 << 7) 105260ecb3cSHaibo Chen #define ESDHC_TUNING_STEP_MASK 0x00070000 106d407e30bSHaibo Chen #define ESDHC_TUNING_STEP_SHIFT 16 1076e9fd28eSDong Aisheng 108ad93220dSDong Aisheng /* pinctrl state */ 109ad93220dSDong Aisheng #define ESDHC_PINCTRL_STATE_100MHZ "state_100mhz" 110ad93220dSDong Aisheng #define ESDHC_PINCTRL_STATE_200MHZ "state_200mhz" 111ad93220dSDong Aisheng 11258ac8177SRichard Zhu /* 113af51079eSSascha Hauer * Our interpretation of the SDHCI_HOST_CONTROL register 114af51079eSSascha Hauer */ 115af51079eSSascha Hauer #define ESDHC_CTRL_4BITBUS (0x1 << 1) 116af51079eSSascha Hauer #define ESDHC_CTRL_8BITBUS (0x2 << 1) 117af51079eSSascha Hauer #define ESDHC_CTRL_BUSWIDTH_MASK (0x3 << 1) 118af51079eSSascha Hauer 119af51079eSSascha Hauer /* 120d04f8d5bSBenoît Thébaudeau * There is an INT DMA ERR mismatch between eSDHC and STD SDHC SPEC: 12197e4ba6aSRichard Zhu * Bit25 is used in STD SPEC, and is reserved in fsl eSDHC design, 12297e4ba6aSRichard Zhu * but bit28 is used as the INT DMA ERR in fsl eSDHC design. 12397e4ba6aSRichard Zhu * Define this macro DMA error INT for fsl eSDHC 12497e4ba6aSRichard Zhu */ 12560bf6396SShawn Guo #define ESDHC_INT_VENDOR_SPEC_DMA_ERR (1 << 28) 12697e4ba6aSRichard Zhu 127bb6e3581SBOUGH CHEN /* the address offset of CQHCI */ 128bb6e3581SBOUGH CHEN #define ESDHC_CQHCI_ADDR_OFFSET 0x100 129bb6e3581SBOUGH CHEN 13097e4ba6aSRichard Zhu /* 13158ac8177SRichard Zhu * The CMDTYPE of the CMD register (offset 0xE) should be set to 13258ac8177SRichard Zhu * "11" when the STOP CMD12 is issued on imx53 to abort one 13358ac8177SRichard Zhu * open ended multi-blk IO. Otherwise the TC INT wouldn't 13458ac8177SRichard Zhu * be generated. 13558ac8177SRichard Zhu * In exact block transfer, the controller doesn't complete the 13658ac8177SRichard Zhu * operations automatically as required at the end of the 13758ac8177SRichard Zhu * transfer and remains on hold if the abort command is not sent. 13858ac8177SRichard Zhu * As a result, the TC flag is not asserted and SW received timeout 139d04f8d5bSBenoît Thébaudeau * exception. Bit1 of Vendor Spec register is used to fix it. 14058ac8177SRichard Zhu */ 14131fbb301SShawn Guo #define ESDHC_FLAG_MULTIBLK_NO_INT BIT(1) 14231fbb301SShawn Guo /* 1439d61c009SShawn Guo * The flag tells that the ESDHC controller is an USDHC block that is 1449d61c009SShawn Guo * integrated on the i.MX6 series. 1459d61c009SShawn Guo */ 1469d61c009SShawn Guo #define ESDHC_FLAG_USDHC BIT(3) 1476e9fd28eSDong Aisheng /* The IP supports manual tuning process */ 1486e9fd28eSDong Aisheng #define ESDHC_FLAG_MAN_TUNING BIT(4) 1496e9fd28eSDong Aisheng /* The IP supports standard tuning process */ 1506e9fd28eSDong Aisheng #define ESDHC_FLAG_STD_TUNING BIT(5) 1516e9fd28eSDong Aisheng /* The IP has SDHCI_CAPABILITIES_1 register */ 1526e9fd28eSDong Aisheng #define ESDHC_FLAG_HAVE_CAP1 BIT(6) 15318094430SDong Aisheng /* 154d04f8d5bSBenoît Thébaudeau * The IP has erratum ERR004536 15518094430SDong Aisheng * uSDHC: ADMA Length Mismatch Error occurs if the AHB read access is slow, 15618094430SDong Aisheng * when reading data from the card 157667123f6SBenoît Thébaudeau * This flag is also set for i.MX25 and i.MX35 in order to get 158667123f6SBenoît Thébaudeau * SDHCI_QUIRK_BROKEN_ADMA, but for different reasons (ADMA capability bits). 15918094430SDong Aisheng */ 16018094430SDong Aisheng #define ESDHC_FLAG_ERR004536 BIT(7) 1614245afffSDong Aisheng /* The IP supports HS200 mode */ 1624245afffSDong Aisheng #define ESDHC_FLAG_HS200 BIT(8) 16328b07674SHaibo Chen /* The IP supports HS400 mode */ 16428b07674SHaibo Chen #define ESDHC_FLAG_HS400 BIT(9) 165af6a50d4SBOUGH CHEN /* 166af6a50d4SBOUGH CHEN * The IP has errata ERR010450 167af6a50d4SBOUGH CHEN * uSDHC: Due to the I/O timing limit, for SDR mode, SD card clock can't 168af6a50d4SBOUGH CHEN * exceed 150MHz, for DDR mode, SD card clock can't exceed 45MHz. 169af6a50d4SBOUGH CHEN */ 170af6a50d4SBOUGH CHEN #define ESDHC_FLAG_ERR010450 BIT(10) 171029e2476SBOUGH CHEN /* The IP supports HS400ES mode */ 172029e2476SBOUGH CHEN #define ESDHC_FLAG_HS400_ES BIT(11) 173bb6e3581SBOUGH CHEN /* The IP has Host Controller Interface for Command Queuing */ 174bb6e3581SBOUGH CHEN #define ESDHC_FLAG_CQHCI BIT(12) 1751c4989b0SBOUGH CHEN /* need request pmqos during low power */ 1761c4989b0SBOUGH CHEN #define ESDHC_FLAG_PMQOS BIT(13) 177a26a4f1bSHaibo Chen /* The IP state got lost in low power mode */ 178a26a4f1bSHaibo Chen #define ESDHC_FLAG_STATE_LOST_IN_LPMODE BIT(14) 1795c11f1ffSHaibo Chen /* The IP lost clock rate in PM_RUNTIME */ 1805c11f1ffSHaibo Chen #define ESDHC_FLAG_CLK_RATE_LOST_IN_PM_RUNTIME BIT(15) 18174898cbcSHaibo Chen /* 18274898cbcSHaibo Chen * The IP do not support the ACMD23 feature completely when use ADMA mode. 18374898cbcSHaibo Chen * In ADMA mode, it only use the 16 bit block count of the register 0x4 18474898cbcSHaibo Chen * (BLOCK_ATT) as the CMD23's argument for ACMD23 mode, which means it will 18574898cbcSHaibo Chen * ignore the upper 16 bit of the CMD23's argument. This will block the reliable 18674898cbcSHaibo Chen * write operation in RPMB, because RPMB reliable write need to set the bit31 18774898cbcSHaibo Chen * of the CMD23's argument. 18874898cbcSHaibo Chen * imx6qpdl/imx6sx/imx6sl/imx7d has this limitation only for ADMA mode, SDMA 18974898cbcSHaibo Chen * do not has this limitation. so when these SoC use ADMA mode, it need to 19074898cbcSHaibo Chen * disable the ACMD23 feature. 19174898cbcSHaibo Chen */ 19274898cbcSHaibo Chen #define ESDHC_FLAG_BROKEN_AUTO_CMD23 BIT(16) 193e149860dSRichard Zhu 194f47c4bbfSShawn Guo struct esdhc_soc_data { 195f47c4bbfSShawn Guo u32 flags; 196f47c4bbfSShawn Guo }; 197f47c4bbfSShawn Guo 1984f100012SAndrey Smirnov static const struct esdhc_soc_data esdhc_imx25_data = { 199667123f6SBenoît Thébaudeau .flags = ESDHC_FLAG_ERR004536, 200f47c4bbfSShawn Guo }; 201f47c4bbfSShawn Guo 2024f100012SAndrey Smirnov static const struct esdhc_soc_data esdhc_imx35_data = { 203667123f6SBenoît Thébaudeau .flags = ESDHC_FLAG_ERR004536, 204f47c4bbfSShawn Guo }; 205f47c4bbfSShawn Guo 2064f100012SAndrey Smirnov static const struct esdhc_soc_data esdhc_imx51_data = { 207f47c4bbfSShawn Guo .flags = 0, 208f47c4bbfSShawn Guo }; 209f47c4bbfSShawn Guo 2104f100012SAndrey Smirnov static const struct esdhc_soc_data esdhc_imx53_data = { 211f47c4bbfSShawn Guo .flags = ESDHC_FLAG_MULTIBLK_NO_INT, 212f47c4bbfSShawn Guo }; 213f47c4bbfSShawn Guo 2144f100012SAndrey Smirnov static const struct esdhc_soc_data usdhc_imx6q_data = { 21574898cbcSHaibo Chen .flags = ESDHC_FLAG_USDHC | ESDHC_FLAG_MAN_TUNING 21674898cbcSHaibo Chen | ESDHC_FLAG_BROKEN_AUTO_CMD23, 2176e9fd28eSDong Aisheng }; 2186e9fd28eSDong Aisheng 2194f100012SAndrey Smirnov static const struct esdhc_soc_data usdhc_imx6sl_data = { 2206e9fd28eSDong Aisheng .flags = ESDHC_FLAG_USDHC | ESDHC_FLAG_STD_TUNING 2214245afffSDong Aisheng | ESDHC_FLAG_HAVE_CAP1 | ESDHC_FLAG_ERR004536 22274898cbcSHaibo Chen | ESDHC_FLAG_HS200 22374898cbcSHaibo Chen | ESDHC_FLAG_BROKEN_AUTO_CMD23, 22474898cbcSHaibo Chen }; 22574898cbcSHaibo Chen 22674898cbcSHaibo Chen static const struct esdhc_soc_data usdhc_imx6sll_data = { 22774898cbcSHaibo Chen .flags = ESDHC_FLAG_USDHC | ESDHC_FLAG_STD_TUNING 22874898cbcSHaibo Chen | ESDHC_FLAG_HAVE_CAP1 | ESDHC_FLAG_HS200 22986b59671SHaibo Chen | ESDHC_FLAG_HS400 23074898cbcSHaibo Chen | ESDHC_FLAG_STATE_LOST_IN_LPMODE, 23157ed3314SShawn Guo }; 23257ed3314SShawn Guo 2334f100012SAndrey Smirnov static const struct esdhc_soc_data usdhc_imx6sx_data = { 234913d4951SDong Aisheng .flags = ESDHC_FLAG_USDHC | ESDHC_FLAG_STD_TUNING 235a26a4f1bSHaibo Chen | ESDHC_FLAG_HAVE_CAP1 | ESDHC_FLAG_HS200 23674898cbcSHaibo Chen | ESDHC_FLAG_STATE_LOST_IN_LPMODE 23774898cbcSHaibo Chen | ESDHC_FLAG_BROKEN_AUTO_CMD23, 238913d4951SDong Aisheng }; 239913d4951SDong Aisheng 240af6a50d4SBOUGH CHEN static const struct esdhc_soc_data usdhc_imx6ull_data = { 241af6a50d4SBOUGH CHEN .flags = ESDHC_FLAG_USDHC | ESDHC_FLAG_STD_TUNING 242af6a50d4SBOUGH CHEN | ESDHC_FLAG_HAVE_CAP1 | ESDHC_FLAG_HS200 243a26a4f1bSHaibo Chen | ESDHC_FLAG_ERR010450 244a26a4f1bSHaibo Chen | ESDHC_FLAG_STATE_LOST_IN_LPMODE, 245af6a50d4SBOUGH CHEN }; 246af6a50d4SBOUGH CHEN 2474f100012SAndrey Smirnov static const struct esdhc_soc_data usdhc_imx7d_data = { 24828b07674SHaibo Chen .flags = ESDHC_FLAG_USDHC | ESDHC_FLAG_STD_TUNING 24928b07674SHaibo Chen | ESDHC_FLAG_HAVE_CAP1 | ESDHC_FLAG_HS200 250a26a4f1bSHaibo Chen | ESDHC_FLAG_HS400 25174898cbcSHaibo Chen | ESDHC_FLAG_STATE_LOST_IN_LPMODE 25274898cbcSHaibo Chen | ESDHC_FLAG_BROKEN_AUTO_CMD23, 25328b07674SHaibo Chen }; 25428b07674SHaibo Chen 2551c4989b0SBOUGH CHEN static struct esdhc_soc_data usdhc_imx7ulp_data = { 2561c4989b0SBOUGH CHEN .flags = ESDHC_FLAG_USDHC | ESDHC_FLAG_STD_TUNING 2571c4989b0SBOUGH CHEN | ESDHC_FLAG_HAVE_CAP1 | ESDHC_FLAG_HS200 258a26a4f1bSHaibo Chen | ESDHC_FLAG_PMQOS | ESDHC_FLAG_HS400 259a26a4f1bSHaibo Chen | ESDHC_FLAG_STATE_LOST_IN_LPMODE, 2601c4989b0SBOUGH CHEN }; 2611c4989b0SBOUGH CHEN 262029e2476SBOUGH CHEN static struct esdhc_soc_data usdhc_imx8qxp_data = { 263029e2476SBOUGH CHEN .flags = ESDHC_FLAG_USDHC | ESDHC_FLAG_STD_TUNING 264029e2476SBOUGH CHEN | ESDHC_FLAG_HAVE_CAP1 | ESDHC_FLAG_HS200 265bb6e3581SBOUGH CHEN | ESDHC_FLAG_HS400 | ESDHC_FLAG_HS400_ES 266a26a4f1bSHaibo Chen | ESDHC_FLAG_CQHCI 2675c11f1ffSHaibo Chen | ESDHC_FLAG_STATE_LOST_IN_LPMODE 2685c11f1ffSHaibo Chen | ESDHC_FLAG_CLK_RATE_LOST_IN_PM_RUNTIME, 269029e2476SBOUGH CHEN }; 270029e2476SBOUGH CHEN 271cde5e8e9SHaibo Chen static struct esdhc_soc_data usdhc_imx8mm_data = { 272cde5e8e9SHaibo Chen .flags = ESDHC_FLAG_USDHC | ESDHC_FLAG_STD_TUNING 273cde5e8e9SHaibo Chen | ESDHC_FLAG_HAVE_CAP1 | ESDHC_FLAG_HS200 274cde5e8e9SHaibo Chen | ESDHC_FLAG_HS400 | ESDHC_FLAG_HS400_ES 275cde5e8e9SHaibo Chen | ESDHC_FLAG_CQHCI 276cde5e8e9SHaibo Chen | ESDHC_FLAG_STATE_LOST_IN_LPMODE, 277e149860dSRichard Zhu }; 278e149860dSRichard Zhu 279e149860dSRichard Zhu struct pltfm_imx_data { 280e149860dSRichard Zhu u32 scratchpad; 281e62d8b8fSDong Aisheng struct pinctrl *pinctrl; 282ad93220dSDong Aisheng struct pinctrl_state *pins_100mhz; 283ad93220dSDong Aisheng struct pinctrl_state *pins_200mhz; 284f47c4bbfSShawn Guo const struct esdhc_soc_data *socdata; 285842afc02SShawn Guo struct esdhc_platform_data boarddata; 28652dac615SSascha Hauer struct clk *clk_ipg; 28752dac615SSascha Hauer struct clk *clk_ahb; 28852dac615SSascha Hauer struct clk *clk_per; 2893602785bSMichael Trimarchi unsigned int actual_clock; 290361b8482SLucas Stach enum { 291361b8482SLucas Stach NO_CMD_PENDING, /* no multiblock command pending */ 292361b8482SLucas Stach MULTIBLK_IN_PROCESS, /* exact multiblock cmd in process */ 293361b8482SLucas Stach WAIT_FOR_INT, /* sent CMD12, waiting for response INT */ 294361b8482SLucas Stach } multiblock_status; 295de5bdbffSDong Aisheng u32 is_ddr; 2961c4989b0SBOUGH CHEN struct pm_qos_request pm_qos_req; 297e149860dSRichard Zhu }; 298e149860dSRichard Zhu 299f8cbf461SKrzysztof Kozlowski static const struct platform_device_id imx_esdhc_devtype[] = { 30057ed3314SShawn Guo { 30157ed3314SShawn Guo .name = "sdhci-esdhc-imx25", 302f47c4bbfSShawn Guo .driver_data = (kernel_ulong_t) &esdhc_imx25_data, 30357ed3314SShawn Guo }, { 30457ed3314SShawn Guo .name = "sdhci-esdhc-imx35", 305f47c4bbfSShawn Guo .driver_data = (kernel_ulong_t) &esdhc_imx35_data, 30657ed3314SShawn Guo }, { 30757ed3314SShawn Guo .name = "sdhci-esdhc-imx51", 308f47c4bbfSShawn Guo .driver_data = (kernel_ulong_t) &esdhc_imx51_data, 30957ed3314SShawn Guo }, { 31057ed3314SShawn Guo /* sentinel */ 31157ed3314SShawn Guo } 31257ed3314SShawn Guo }; 31357ed3314SShawn Guo MODULE_DEVICE_TABLE(platform, imx_esdhc_devtype); 31457ed3314SShawn Guo 315abfafc2dSShawn Guo static const struct of_device_id imx_esdhc_dt_ids[] = { 316f47c4bbfSShawn Guo { .compatible = "fsl,imx25-esdhc", .data = &esdhc_imx25_data, }, 317f47c4bbfSShawn Guo { .compatible = "fsl,imx35-esdhc", .data = &esdhc_imx35_data, }, 318f47c4bbfSShawn Guo { .compatible = "fsl,imx51-esdhc", .data = &esdhc_imx51_data, }, 319f47c4bbfSShawn Guo { .compatible = "fsl,imx53-esdhc", .data = &esdhc_imx53_data, }, 320913d4951SDong Aisheng { .compatible = "fsl,imx6sx-usdhc", .data = &usdhc_imx6sx_data, }, 3216e9fd28eSDong Aisheng { .compatible = "fsl,imx6sl-usdhc", .data = &usdhc_imx6sl_data, }, 32274898cbcSHaibo Chen { .compatible = "fsl,imx6sll-usdhc", .data = &usdhc_imx6sll_data, }, 323f47c4bbfSShawn Guo { .compatible = "fsl,imx6q-usdhc", .data = &usdhc_imx6q_data, }, 324af6a50d4SBOUGH CHEN { .compatible = "fsl,imx6ull-usdhc", .data = &usdhc_imx6ull_data, }, 32528b07674SHaibo Chen { .compatible = "fsl,imx7d-usdhc", .data = &usdhc_imx7d_data, }, 3261c4989b0SBOUGH CHEN { .compatible = "fsl,imx7ulp-usdhc", .data = &usdhc_imx7ulp_data, }, 327029e2476SBOUGH CHEN { .compatible = "fsl,imx8qxp-usdhc", .data = &usdhc_imx8qxp_data, }, 328cde5e8e9SHaibo Chen { .compatible = "fsl,imx8mm-usdhc", .data = &usdhc_imx8mm_data, }, 329abfafc2dSShawn Guo { /* sentinel */ } 330abfafc2dSShawn Guo }; 331abfafc2dSShawn Guo MODULE_DEVICE_TABLE(of, imx_esdhc_dt_ids); 332abfafc2dSShawn Guo 33357ed3314SShawn Guo static inline int is_imx25_esdhc(struct pltfm_imx_data *data) 33457ed3314SShawn Guo { 335f47c4bbfSShawn Guo return data->socdata == &esdhc_imx25_data; 33657ed3314SShawn Guo } 33757ed3314SShawn Guo 33857ed3314SShawn Guo static inline int is_imx53_esdhc(struct pltfm_imx_data *data) 33957ed3314SShawn Guo { 340f47c4bbfSShawn Guo return data->socdata == &esdhc_imx53_data; 34157ed3314SShawn Guo } 34257ed3314SShawn Guo 34395a2482aSShawn Guo static inline int is_imx6q_usdhc(struct pltfm_imx_data *data) 34495a2482aSShawn Guo { 345f47c4bbfSShawn Guo return data->socdata == &usdhc_imx6q_data; 34695a2482aSShawn Guo } 34795a2482aSShawn Guo 3489d61c009SShawn Guo static inline int esdhc_is_usdhc(struct pltfm_imx_data *data) 3499d61c009SShawn Guo { 350f47c4bbfSShawn Guo return !!(data->socdata->flags & ESDHC_FLAG_USDHC); 3519d61c009SShawn Guo } 3529d61c009SShawn Guo 35395f25efeSWolfram Sang static inline void esdhc_clrset_le(struct sdhci_host *host, u32 mask, u32 val, int reg) 35495f25efeSWolfram Sang { 35595f25efeSWolfram Sang void __iomem *base = host->ioaddr + (reg & ~0x3); 35695f25efeSWolfram Sang u32 shift = (reg & 0x3) * 8; 35795f25efeSWolfram Sang 35895f25efeSWolfram Sang writel(((readl(base) & ~(mask << shift)) | (val << shift)), base); 35995f25efeSWolfram Sang } 36095f25efeSWolfram Sang 3613722c74cSHaibo Chen #define DRIVER_NAME "sdhci-esdhc-imx" 3623722c74cSHaibo Chen #define ESDHC_IMX_DUMP(f, x...) \ 3633722c74cSHaibo Chen pr_err("%s: " DRIVER_NAME ": " f, mmc_hostname(host->mmc), ## x) 3643722c74cSHaibo Chen static void esdhc_dump_debug_regs(struct sdhci_host *host) 3653722c74cSHaibo Chen { 3663722c74cSHaibo Chen int i; 3673722c74cSHaibo Chen char *debug_status[7] = { 3683722c74cSHaibo Chen "cmd debug status", 3693722c74cSHaibo Chen "data debug status", 3703722c74cSHaibo Chen "trans debug status", 3713722c74cSHaibo Chen "dma debug status", 3723722c74cSHaibo Chen "adma debug status", 3733722c74cSHaibo Chen "fifo debug status", 3743722c74cSHaibo Chen "async fifo debug status" 3753722c74cSHaibo Chen }; 3763722c74cSHaibo Chen 3773722c74cSHaibo Chen ESDHC_IMX_DUMP("========= ESDHC IMX DEBUG STATUS DUMP =========\n"); 3783722c74cSHaibo Chen for (i = 0; i < 7; i++) { 3793722c74cSHaibo Chen esdhc_clrset_le(host, ESDHC_DEBUG_SEL_MASK, 3803722c74cSHaibo Chen ESDHC_DEBUG_SEL_CMD_STATE + i, ESDHC_DEBUG_SEL_REG); 3813722c74cSHaibo Chen ESDHC_IMX_DUMP("%s: 0x%04x\n", debug_status[i], 3823722c74cSHaibo Chen readw(host->ioaddr + ESDHC_DEBUG_SEL_AND_STATUS_REG)); 3833722c74cSHaibo Chen } 3843722c74cSHaibo Chen 3853722c74cSHaibo Chen esdhc_clrset_le(host, ESDHC_DEBUG_SEL_MASK, 0, ESDHC_DEBUG_SEL_REG); 3863722c74cSHaibo Chen 3873722c74cSHaibo Chen } 3883722c74cSHaibo Chen 389f581e909SHaibo Chen static inline void esdhc_wait_for_card_clock_gate_off(struct sdhci_host *host) 390f581e909SHaibo Chen { 391f581e909SHaibo Chen u32 present_state; 392f581e909SHaibo Chen int ret; 393f581e909SHaibo Chen 394f581e909SHaibo Chen ret = readl_poll_timeout(host->ioaddr + ESDHC_PRSSTAT, present_state, 395f581e909SHaibo Chen (present_state & ESDHC_CLOCK_GATE_OFF), 2, 100); 396f581e909SHaibo Chen if (ret == -ETIMEDOUT) 397f581e909SHaibo Chen dev_warn(mmc_dev(host->mmc), "%s: card clock still not gate off in 100us!.\n", __func__); 398f581e909SHaibo Chen } 399f581e909SHaibo Chen 4007e29c306SWolfram Sang static u32 esdhc_readl_le(struct sdhci_host *host, int reg) 4017e29c306SWolfram Sang { 402361b8482SLucas Stach struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); 403070e6d3fSJisheng Zhang struct pltfm_imx_data *imx_data = sdhci_pltfm_priv(pltfm_host); 404913413c3SShawn Guo u32 val = readl(host->ioaddr + reg); 405913413c3SShawn Guo 4060322191eSDong Aisheng if (unlikely(reg == SDHCI_PRESENT_STATE)) { 4070322191eSDong Aisheng u32 fsl_prss = val; 4080322191eSDong Aisheng /* save the least 20 bits */ 4090322191eSDong Aisheng val = fsl_prss & 0x000FFFFF; 4100322191eSDong Aisheng /* move dat[0-3] bits */ 4110322191eSDong Aisheng val |= (fsl_prss & 0x0F000000) >> 4; 4120322191eSDong Aisheng /* move cmd line bit */ 4130322191eSDong Aisheng val |= (fsl_prss & 0x00800000) << 1; 4140322191eSDong Aisheng } 4150322191eSDong Aisheng 41697e4ba6aSRichard Zhu if (unlikely(reg == SDHCI_CAPABILITIES)) { 4176b4fb671SDong Aisheng /* ignore bit[0-15] as it stores cap_1 register val for mx6sl */ 4186b4fb671SDong Aisheng if (imx_data->socdata->flags & ESDHC_FLAG_HAVE_CAP1) 4196b4fb671SDong Aisheng val &= 0xffff0000; 4206b4fb671SDong Aisheng 42197e4ba6aSRichard Zhu /* In FSL esdhc IC module, only bit20 is used to indicate the 42297e4ba6aSRichard Zhu * ADMA2 capability of esdhc, but this bit is messed up on 42397e4ba6aSRichard Zhu * some SOCs (e.g. on MX25, MX35 this bit is set, but they 42497e4ba6aSRichard Zhu * don't actually support ADMA2). So set the BROKEN_ADMA 425d04f8d5bSBenoît Thébaudeau * quirk on MX25/35 platforms. 42697e4ba6aSRichard Zhu */ 42797e4ba6aSRichard Zhu 42897e4ba6aSRichard Zhu if (val & SDHCI_CAN_DO_ADMA1) { 42997e4ba6aSRichard Zhu val &= ~SDHCI_CAN_DO_ADMA1; 43097e4ba6aSRichard Zhu val |= SDHCI_CAN_DO_ADMA2; 43197e4ba6aSRichard Zhu } 43297e4ba6aSRichard Zhu } 43397e4ba6aSRichard Zhu 4346e9fd28eSDong Aisheng if (unlikely(reg == SDHCI_CAPABILITIES_1)) { 4356e9fd28eSDong Aisheng if (esdhc_is_usdhc(imx_data)) { 4366e9fd28eSDong Aisheng if (imx_data->socdata->flags & ESDHC_FLAG_HAVE_CAP1) 4376e9fd28eSDong Aisheng val = readl(host->ioaddr + SDHCI_CAPABILITIES) & 0xFFFF; 4386e9fd28eSDong Aisheng else 4396e9fd28eSDong Aisheng /* imx6q/dl does not have cap_1 register, fake one */ 4400322191eSDong Aisheng val = SDHCI_SUPPORT_DDR50 | SDHCI_SUPPORT_SDR104 441888824bbSDong Aisheng | SDHCI_SUPPORT_SDR50 442da0295ffSDong Aisheng | SDHCI_USE_SDR50_TUNING 443a8e809ecSMasahiro Yamada | FIELD_PREP(SDHCI_RETUNING_MODE_MASK, 444a8e809ecSMasahiro Yamada SDHCI_TUNING_MODE_3); 44528b07674SHaibo Chen 44628b07674SHaibo Chen if (imx_data->socdata->flags & ESDHC_FLAG_HS400) 44728b07674SHaibo Chen val |= SDHCI_SUPPORT_HS400; 44892748beaSStefan Agner 44992748beaSStefan Agner /* 45092748beaSStefan Agner * Do not advertise faster UHS modes if there are no 45192748beaSStefan Agner * pinctrl states for 100MHz/200MHz. 45292748beaSStefan Agner */ 45392748beaSStefan Agner if (IS_ERR_OR_NULL(imx_data->pins_100mhz) || 45492748beaSStefan Agner IS_ERR_OR_NULL(imx_data->pins_200mhz)) 45592748beaSStefan Agner val &= ~(SDHCI_SUPPORT_SDR50 | SDHCI_SUPPORT_DDR50 45692748beaSStefan Agner | SDHCI_SUPPORT_SDR104 | SDHCI_SUPPORT_HS400); 4576e9fd28eSDong Aisheng } 4586e9fd28eSDong Aisheng } 4590322191eSDong Aisheng 4609d61c009SShawn Guo if (unlikely(reg == SDHCI_MAX_CURRENT) && esdhc_is_usdhc(imx_data)) { 4610322191eSDong Aisheng val = 0; 462804a65b3SMasahiro Yamada val |= FIELD_PREP(SDHCI_MAX_CURRENT_330_MASK, 0xFF); 463804a65b3SMasahiro Yamada val |= FIELD_PREP(SDHCI_MAX_CURRENT_300_MASK, 0xFF); 464804a65b3SMasahiro Yamada val |= FIELD_PREP(SDHCI_MAX_CURRENT_180_MASK, 0xFF); 4650322191eSDong Aisheng } 4660322191eSDong Aisheng 46797e4ba6aSRichard Zhu if (unlikely(reg == SDHCI_INT_STATUS)) { 46860bf6396SShawn Guo if (val & ESDHC_INT_VENDOR_SPEC_DMA_ERR) { 46960bf6396SShawn Guo val &= ~ESDHC_INT_VENDOR_SPEC_DMA_ERR; 47097e4ba6aSRichard Zhu val |= SDHCI_INT_ADMA_ERROR; 47197e4ba6aSRichard Zhu } 472361b8482SLucas Stach 473361b8482SLucas Stach /* 474361b8482SLucas Stach * mask off the interrupt we get in response to the manually 475361b8482SLucas Stach * sent CMD12 476361b8482SLucas Stach */ 477361b8482SLucas Stach if ((imx_data->multiblock_status == WAIT_FOR_INT) && 478361b8482SLucas Stach ((val & SDHCI_INT_RESPONSE) == SDHCI_INT_RESPONSE)) { 479361b8482SLucas Stach val &= ~SDHCI_INT_RESPONSE; 480361b8482SLucas Stach writel(SDHCI_INT_RESPONSE, host->ioaddr + 481361b8482SLucas Stach SDHCI_INT_STATUS); 482361b8482SLucas Stach imx_data->multiblock_status = NO_CMD_PENDING; 483361b8482SLucas Stach } 48497e4ba6aSRichard Zhu } 48597e4ba6aSRichard Zhu 4867e29c306SWolfram Sang return val; 4877e29c306SWolfram Sang } 4887e29c306SWolfram Sang 4897e29c306SWolfram Sang static void esdhc_writel_le(struct sdhci_host *host, u32 val, int reg) 4907e29c306SWolfram Sang { 491e149860dSRichard Zhu struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); 492070e6d3fSJisheng Zhang struct pltfm_imx_data *imx_data = sdhci_pltfm_priv(pltfm_host); 4930d58864bSTony Lin u32 data; 494e149860dSRichard Zhu 49577da3da0SAaron Brice if (unlikely(reg == SDHCI_INT_ENABLE || reg == SDHCI_SIGNAL_ENABLE || 49677da3da0SAaron Brice reg == SDHCI_INT_STATUS)) { 497b7321042SDong Aisheng if ((val & SDHCI_INT_CARD_INT) && !esdhc_is_usdhc(imx_data)) { 4980d58864bSTony Lin /* 4990d58864bSTony Lin * Clear and then set D3CD bit to avoid missing the 500d04f8d5bSBenoît Thébaudeau * card interrupt. This is an eSDHC controller problem 5010d58864bSTony Lin * so we need to apply the following workaround: clear 5020d58864bSTony Lin * and set D3CD bit will make eSDHC re-sample the card 5030d58864bSTony Lin * interrupt. In case a card interrupt was lost, 5040d58864bSTony Lin * re-sample it by the following steps. 5050d58864bSTony Lin */ 5060d58864bSTony Lin data = readl(host->ioaddr + SDHCI_HOST_CONTROL); 50760bf6396SShawn Guo data &= ~ESDHC_CTRL_D3CD; 5080d58864bSTony Lin writel(data, host->ioaddr + SDHCI_HOST_CONTROL); 50960bf6396SShawn Guo data |= ESDHC_CTRL_D3CD; 5100d58864bSTony Lin writel(data, host->ioaddr + SDHCI_HOST_CONTROL); 5110d58864bSTony Lin } 512915be485SDong Aisheng 513915be485SDong Aisheng if (val & SDHCI_INT_ADMA_ERROR) { 514915be485SDong Aisheng val &= ~SDHCI_INT_ADMA_ERROR; 515915be485SDong Aisheng val |= ESDHC_INT_VENDOR_SPEC_DMA_ERR; 516915be485SDong Aisheng } 5170d58864bSTony Lin } 5180d58864bSTony Lin 519f47c4bbfSShawn Guo if (unlikely((imx_data->socdata->flags & ESDHC_FLAG_MULTIBLK_NO_INT) 52058ac8177SRichard Zhu && (reg == SDHCI_INT_STATUS) 52158ac8177SRichard Zhu && (val & SDHCI_INT_DATA_END))) { 52258ac8177SRichard Zhu u32 v; 52360bf6396SShawn Guo v = readl(host->ioaddr + ESDHC_VENDOR_SPEC); 52460bf6396SShawn Guo v &= ~ESDHC_VENDOR_SPEC_SDIO_QUIRK; 52560bf6396SShawn Guo writel(v, host->ioaddr + ESDHC_VENDOR_SPEC); 526361b8482SLucas Stach 527361b8482SLucas Stach if (imx_data->multiblock_status == MULTIBLK_IN_PROCESS) 528361b8482SLucas Stach { 529361b8482SLucas Stach /* send a manual CMD12 with RESPTYP=none */ 530361b8482SLucas Stach data = MMC_STOP_TRANSMISSION << 24 | 531361b8482SLucas Stach SDHCI_CMD_ABORTCMD << 16; 532361b8482SLucas Stach writel(data, host->ioaddr + SDHCI_TRANSFER_MODE); 533361b8482SLucas Stach imx_data->multiblock_status = WAIT_FOR_INT; 534361b8482SLucas Stach } 53558ac8177SRichard Zhu } 53658ac8177SRichard Zhu 5377e29c306SWolfram Sang writel(val, host->ioaddr + reg); 5387e29c306SWolfram Sang } 5397e29c306SWolfram Sang 54095f25efeSWolfram Sang static u16 esdhc_readw_le(struct sdhci_host *host, int reg) 54195f25efeSWolfram Sang { 542ef4d0888SShawn Guo struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); 543070e6d3fSJisheng Zhang struct pltfm_imx_data *imx_data = sdhci_pltfm_priv(pltfm_host); 5440322191eSDong Aisheng u16 ret = 0; 5450322191eSDong Aisheng u32 val; 546ef4d0888SShawn Guo 54795a2482aSShawn Guo if (unlikely(reg == SDHCI_HOST_VERSION)) { 548ef4d0888SShawn Guo reg ^= 2; 5499d61c009SShawn Guo if (esdhc_is_usdhc(imx_data)) { 55095a2482aSShawn Guo /* 551ef4d0888SShawn Guo * The usdhc register returns a wrong host version. 552ef4d0888SShawn Guo * Correct it here. 55395a2482aSShawn Guo */ 554ef4d0888SShawn Guo return SDHCI_SPEC_300; 555ef4d0888SShawn Guo } 55695a2482aSShawn Guo } 55795f25efeSWolfram Sang 5580322191eSDong Aisheng if (unlikely(reg == SDHCI_HOST_CONTROL2)) { 5590322191eSDong Aisheng val = readl(host->ioaddr + ESDHC_VENDOR_SPEC); 5600322191eSDong Aisheng if (val & ESDHC_VENDOR_SPEC_VSELECT) 5610322191eSDong Aisheng ret |= SDHCI_CTRL_VDD_180; 5620322191eSDong Aisheng 5639d61c009SShawn Guo if (esdhc_is_usdhc(imx_data)) { 5646e9fd28eSDong Aisheng if (imx_data->socdata->flags & ESDHC_FLAG_MAN_TUNING) 5650322191eSDong Aisheng val = readl(host->ioaddr + ESDHC_MIX_CTRL); 5666e9fd28eSDong Aisheng else if (imx_data->socdata->flags & ESDHC_FLAG_STD_TUNING) 5676e9fd28eSDong Aisheng /* the std tuning bits is in ACMD12_ERR for imx6sl */ 568869f8a69SAdrian Hunter val = readl(host->ioaddr + SDHCI_AUTO_CMD_STATUS); 5696e9fd28eSDong Aisheng } 5706e9fd28eSDong Aisheng 5710322191eSDong Aisheng if (val & ESDHC_MIX_CTRL_EXE_TUNE) 5720322191eSDong Aisheng ret |= SDHCI_CTRL_EXEC_TUNING; 5730322191eSDong Aisheng if (val & ESDHC_MIX_CTRL_SMPCLK_SEL) 5740322191eSDong Aisheng ret |= SDHCI_CTRL_TUNED_CLK; 5750322191eSDong Aisheng 5760322191eSDong Aisheng ret &= ~SDHCI_CTRL_PRESET_VAL_ENABLE; 5770322191eSDong Aisheng 5780322191eSDong Aisheng return ret; 5790322191eSDong Aisheng } 5800322191eSDong Aisheng 5817dd109efSDong Aisheng if (unlikely(reg == SDHCI_TRANSFER_MODE)) { 5827dd109efSDong Aisheng if (esdhc_is_usdhc(imx_data)) { 5837dd109efSDong Aisheng u32 m = readl(host->ioaddr + ESDHC_MIX_CTRL); 5847dd109efSDong Aisheng ret = m & ESDHC_MIX_CTRL_SDHCI_MASK; 5857dd109efSDong Aisheng /* Swap AC23 bit */ 5867dd109efSDong Aisheng if (m & ESDHC_MIX_CTRL_AC23EN) { 5877dd109efSDong Aisheng ret &= ~ESDHC_MIX_CTRL_AC23EN; 5887dd109efSDong Aisheng ret |= SDHCI_TRNS_AUTO_CMD23; 5897dd109efSDong Aisheng } 5907dd109efSDong Aisheng } else { 5917dd109efSDong Aisheng ret = readw(host->ioaddr + SDHCI_TRANSFER_MODE); 5927dd109efSDong Aisheng } 5937dd109efSDong Aisheng 5947dd109efSDong Aisheng return ret; 5957dd109efSDong Aisheng } 5967dd109efSDong Aisheng 59795f25efeSWolfram Sang return readw(host->ioaddr + reg); 59895f25efeSWolfram Sang } 59995f25efeSWolfram Sang 60095f25efeSWolfram Sang static void esdhc_writew_le(struct sdhci_host *host, u16 val, int reg) 60195f25efeSWolfram Sang { 60295f25efeSWolfram Sang struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); 603070e6d3fSJisheng Zhang struct pltfm_imx_data *imx_data = sdhci_pltfm_priv(pltfm_host); 6040322191eSDong Aisheng u32 new_val = 0; 60595f25efeSWolfram Sang 60695f25efeSWolfram Sang switch (reg) { 6070322191eSDong Aisheng case SDHCI_CLOCK_CONTROL: 6080322191eSDong Aisheng new_val = readl(host->ioaddr + ESDHC_VENDOR_SPEC); 6090322191eSDong Aisheng if (val & SDHCI_CLOCK_CARD_EN) 6100322191eSDong Aisheng new_val |= ESDHC_VENDOR_SPEC_FRC_SDCLK_ON; 6110322191eSDong Aisheng else 6120322191eSDong Aisheng new_val &= ~ESDHC_VENDOR_SPEC_FRC_SDCLK_ON; 6130322191eSDong Aisheng writel(new_val, host->ioaddr + ESDHC_VENDOR_SPEC); 614f581e909SHaibo Chen if (!(new_val & ESDHC_VENDOR_SPEC_FRC_SDCLK_ON)) 615f581e909SHaibo Chen esdhc_wait_for_card_clock_gate_off(host); 6160322191eSDong Aisheng return; 6170322191eSDong Aisheng case SDHCI_HOST_CONTROL2: 6180322191eSDong Aisheng new_val = readl(host->ioaddr + ESDHC_VENDOR_SPEC); 6190322191eSDong Aisheng if (val & SDHCI_CTRL_VDD_180) 6200322191eSDong Aisheng new_val |= ESDHC_VENDOR_SPEC_VSELECT; 6210322191eSDong Aisheng else 6220322191eSDong Aisheng new_val &= ~ESDHC_VENDOR_SPEC_VSELECT; 6230322191eSDong Aisheng writel(new_val, host->ioaddr + ESDHC_VENDOR_SPEC); 6246e9fd28eSDong Aisheng if (imx_data->socdata->flags & ESDHC_FLAG_MAN_TUNING) { 6250322191eSDong Aisheng new_val = readl(host->ioaddr + ESDHC_MIX_CTRL); 626da0295ffSDong Aisheng if (val & SDHCI_CTRL_TUNED_CLK) { 6270322191eSDong Aisheng new_val |= ESDHC_MIX_CTRL_SMPCLK_SEL; 628da0295ffSDong Aisheng new_val |= ESDHC_MIX_CTRL_AUTO_TUNE_EN; 629da0295ffSDong Aisheng } else { 6300322191eSDong Aisheng new_val &= ~ESDHC_MIX_CTRL_SMPCLK_SEL; 631da0295ffSDong Aisheng new_val &= ~ESDHC_MIX_CTRL_AUTO_TUNE_EN; 632da0295ffSDong Aisheng } 6330322191eSDong Aisheng writel(new_val , host->ioaddr + ESDHC_MIX_CTRL); 6346e9fd28eSDong Aisheng } else if (imx_data->socdata->flags & ESDHC_FLAG_STD_TUNING) { 635869f8a69SAdrian Hunter u32 v = readl(host->ioaddr + SDHCI_AUTO_CMD_STATUS); 6366e9fd28eSDong Aisheng u32 m = readl(host->ioaddr + ESDHC_MIX_CTRL); 6378b2bb0adSDong Aisheng if (val & SDHCI_CTRL_TUNED_CLK) { 6388b2bb0adSDong Aisheng v |= ESDHC_MIX_CTRL_SMPCLK_SEL; 6396e9fd28eSDong Aisheng } else { 6408b2bb0adSDong Aisheng v &= ~ESDHC_MIX_CTRL_SMPCLK_SEL; 6416e9fd28eSDong Aisheng m &= ~ESDHC_MIX_CTRL_FBCLK_SEL; 6420b330e38SDong Aisheng m &= ~ESDHC_MIX_CTRL_AUTO_TUNE_EN; 6436e9fd28eSDong Aisheng } 6446e9fd28eSDong Aisheng 6458b2bb0adSDong Aisheng if (val & SDHCI_CTRL_EXEC_TUNING) { 6468b2bb0adSDong Aisheng v |= ESDHC_MIX_CTRL_EXE_TUNE; 6478b2bb0adSDong Aisheng m |= ESDHC_MIX_CTRL_FBCLK_SEL; 6480b330e38SDong Aisheng m |= ESDHC_MIX_CTRL_AUTO_TUNE_EN; 6498b2bb0adSDong Aisheng } else { 6508b2bb0adSDong Aisheng v &= ~ESDHC_MIX_CTRL_EXE_TUNE; 6518b2bb0adSDong Aisheng } 6526e9fd28eSDong Aisheng 653869f8a69SAdrian Hunter writel(v, host->ioaddr + SDHCI_AUTO_CMD_STATUS); 6546e9fd28eSDong Aisheng writel(m, host->ioaddr + ESDHC_MIX_CTRL); 6556e9fd28eSDong Aisheng } 6560322191eSDong Aisheng return; 65795f25efeSWolfram Sang case SDHCI_TRANSFER_MODE: 658f47c4bbfSShawn Guo if ((imx_data->socdata->flags & ESDHC_FLAG_MULTIBLK_NO_INT) 65958ac8177SRichard Zhu && (host->cmd->opcode == SD_IO_RW_EXTENDED) 66058ac8177SRichard Zhu && (host->cmd->data->blocks > 1) 66158ac8177SRichard Zhu && (host->cmd->data->flags & MMC_DATA_READ)) { 66258ac8177SRichard Zhu u32 v; 66360bf6396SShawn Guo v = readl(host->ioaddr + ESDHC_VENDOR_SPEC); 66460bf6396SShawn Guo v |= ESDHC_VENDOR_SPEC_SDIO_QUIRK; 66560bf6396SShawn Guo writel(v, host->ioaddr + ESDHC_VENDOR_SPEC); 66658ac8177SRichard Zhu } 66769f54698SShawn Guo 6689d61c009SShawn Guo if (esdhc_is_usdhc(imx_data)) { 6693fbd4322SAndrew Gabbasov u32 wml; 67069f54698SShawn Guo u32 m = readl(host->ioaddr + ESDHC_MIX_CTRL); 6712a15f981SShawn Guo /* Swap AC23 bit */ 6722a15f981SShawn Guo if (val & SDHCI_TRNS_AUTO_CMD23) { 6732a15f981SShawn Guo val &= ~SDHCI_TRNS_AUTO_CMD23; 6742a15f981SShawn Guo val |= ESDHC_MIX_CTRL_AC23EN; 6752a15f981SShawn Guo } 6762a15f981SShawn Guo m = val | (m & ~ESDHC_MIX_CTRL_SDHCI_MASK); 67769f54698SShawn Guo writel(m, host->ioaddr + ESDHC_MIX_CTRL); 6783fbd4322SAndrew Gabbasov 6793fbd4322SAndrew Gabbasov /* Set watermark levels for PIO access to maximum value 6803fbd4322SAndrew Gabbasov * (128 words) to accommodate full 512 bytes buffer. 6813fbd4322SAndrew Gabbasov * For DMA access restore the levels to default value. 6823fbd4322SAndrew Gabbasov */ 6833fbd4322SAndrew Gabbasov m = readl(host->ioaddr + ESDHC_WTMK_LVL); 684e534b82fSHaibo Chen if (val & SDHCI_TRNS_DMA) { 6853fbd4322SAndrew Gabbasov wml = ESDHC_WTMK_LVL_WML_VAL_DEF; 686e534b82fSHaibo Chen } else { 687e534b82fSHaibo Chen u8 ctrl; 6883fbd4322SAndrew Gabbasov wml = ESDHC_WTMK_LVL_WML_VAL_MAX; 689e534b82fSHaibo Chen 690e534b82fSHaibo Chen /* 691e534b82fSHaibo Chen * Since already disable DMA mode, so also need 692e534b82fSHaibo Chen * to clear the DMASEL. Otherwise, for standard 693e534b82fSHaibo Chen * tuning, when send tuning command, usdhc will 694e534b82fSHaibo Chen * still prefetch the ADMA script from wrong 695e534b82fSHaibo Chen * DMA address, then we will see IOMMU report 696e534b82fSHaibo Chen * some error which show lack of TLB mapping. 697e534b82fSHaibo Chen */ 698e534b82fSHaibo Chen ctrl = sdhci_readb(host, SDHCI_HOST_CONTROL); 699e534b82fSHaibo Chen ctrl &= ~SDHCI_CTRL_DMA_MASK; 700e534b82fSHaibo Chen sdhci_writeb(host, ctrl, SDHCI_HOST_CONTROL); 701e534b82fSHaibo Chen } 7023fbd4322SAndrew Gabbasov m &= ~(ESDHC_WTMK_LVL_RD_WML_MASK | 7033fbd4322SAndrew Gabbasov ESDHC_WTMK_LVL_WR_WML_MASK); 7043fbd4322SAndrew Gabbasov m |= (wml << ESDHC_WTMK_LVL_RD_WML_SHIFT) | 7053fbd4322SAndrew Gabbasov (wml << ESDHC_WTMK_LVL_WR_WML_SHIFT); 7063fbd4322SAndrew Gabbasov writel(m, host->ioaddr + ESDHC_WTMK_LVL); 70769f54698SShawn Guo } else { 70869f54698SShawn Guo /* 70969f54698SShawn Guo * Postpone this write, we must do it together with a 71069f54698SShawn Guo * command write that is down below. 71169f54698SShawn Guo */ 712e149860dSRichard Zhu imx_data->scratchpad = val; 71369f54698SShawn Guo } 71495f25efeSWolfram Sang return; 71595f25efeSWolfram Sang case SDHCI_COMMAND: 716361b8482SLucas Stach if (host->cmd->opcode == MMC_STOP_TRANSMISSION) 71758ac8177SRichard Zhu val |= SDHCI_CMD_ABORTCMD; 71895a2482aSShawn Guo 719361b8482SLucas Stach if ((host->cmd->opcode == MMC_SET_BLOCK_COUNT) && 720f47c4bbfSShawn Guo (imx_data->socdata->flags & ESDHC_FLAG_MULTIBLK_NO_INT)) 721361b8482SLucas Stach imx_data->multiblock_status = MULTIBLK_IN_PROCESS; 722361b8482SLucas Stach 7239d61c009SShawn Guo if (esdhc_is_usdhc(imx_data)) 72495a2482aSShawn Guo writel(val << 16, 72595a2482aSShawn Guo host->ioaddr + SDHCI_TRANSFER_MODE); 72669f54698SShawn Guo else 727e149860dSRichard Zhu writel(val << 16 | imx_data->scratchpad, 72895f25efeSWolfram Sang host->ioaddr + SDHCI_TRANSFER_MODE); 72995f25efeSWolfram Sang return; 73095f25efeSWolfram Sang case SDHCI_BLOCK_SIZE: 73195f25efeSWolfram Sang val &= ~SDHCI_MAKE_BLKSZ(0x7, 0); 73295f25efeSWolfram Sang break; 73395f25efeSWolfram Sang } 73495f25efeSWolfram Sang esdhc_clrset_le(host, 0xffff, val, reg); 73595f25efeSWolfram Sang } 73695f25efeSWolfram Sang 73777da3da0SAaron Brice static u8 esdhc_readb_le(struct sdhci_host *host, int reg) 73877da3da0SAaron Brice { 73977da3da0SAaron Brice u8 ret; 74077da3da0SAaron Brice u32 val; 74177da3da0SAaron Brice 74277da3da0SAaron Brice switch (reg) { 74377da3da0SAaron Brice case SDHCI_HOST_CONTROL: 74477da3da0SAaron Brice val = readl(host->ioaddr + reg); 74577da3da0SAaron Brice 74677da3da0SAaron Brice ret = val & SDHCI_CTRL_LED; 74777da3da0SAaron Brice ret |= (val >> 5) & SDHCI_CTRL_DMA_MASK; 74877da3da0SAaron Brice ret |= (val & ESDHC_CTRL_4BITBUS); 74977da3da0SAaron Brice ret |= (val & ESDHC_CTRL_8BITBUS) << 3; 75077da3da0SAaron Brice return ret; 75177da3da0SAaron Brice } 75277da3da0SAaron Brice 75377da3da0SAaron Brice return readb(host->ioaddr + reg); 75477da3da0SAaron Brice } 75577da3da0SAaron Brice 75695f25efeSWolfram Sang static void esdhc_writeb_le(struct sdhci_host *host, u8 val, int reg) 75795f25efeSWolfram Sang { 7589a0985b7SWilson Callan struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); 759070e6d3fSJisheng Zhang struct pltfm_imx_data *imx_data = sdhci_pltfm_priv(pltfm_host); 76081a0a8bcSBenoît Thébaudeau u32 new_val = 0; 761af51079eSSascha Hauer u32 mask; 76295f25efeSWolfram Sang 76395f25efeSWolfram Sang switch (reg) { 76495f25efeSWolfram Sang case SDHCI_POWER_CONTROL: 76595f25efeSWolfram Sang /* 76695f25efeSWolfram Sang * FSL put some DMA bits here 76795f25efeSWolfram Sang * If your board has a regulator, code should be here 76895f25efeSWolfram Sang */ 76995f25efeSWolfram Sang return; 77095f25efeSWolfram Sang case SDHCI_HOST_CONTROL: 7716b40d182SShawn Guo /* FSL messed up here, so we need to manually compose it. */ 772af51079eSSascha Hauer new_val = val & SDHCI_CTRL_LED; 7737122bbb0SMasanari Iida /* ensure the endianness */ 77495f25efeSWolfram Sang new_val |= ESDHC_HOST_CONTROL_LE; 7759a0985b7SWilson Callan /* bits 8&9 are reserved on mx25 */ 7769a0985b7SWilson Callan if (!is_imx25_esdhc(imx_data)) { 77795f25efeSWolfram Sang /* DMA mode bits are shifted */ 77895f25efeSWolfram Sang new_val |= (val & SDHCI_CTRL_DMA_MASK) << 5; 7799a0985b7SWilson Callan } 78095f25efeSWolfram Sang 781af51079eSSascha Hauer /* 782af51079eSSascha Hauer * Do not touch buswidth bits here. This is done in 783af51079eSSascha Hauer * esdhc_pltfm_bus_width. 784f6825748SMartin Fuzzey * Do not touch the D3CD bit either which is used for the 785d04f8d5bSBenoît Thébaudeau * SDIO interrupt erratum workaround. 786af51079eSSascha Hauer */ 787f6825748SMartin Fuzzey mask = 0xffff & ~(ESDHC_CTRL_BUSWIDTH_MASK | ESDHC_CTRL_D3CD); 788af51079eSSascha Hauer 789af51079eSSascha Hauer esdhc_clrset_le(host, mask, new_val, reg); 79095f25efeSWolfram Sang return; 79181a0a8bcSBenoît Thébaudeau case SDHCI_SOFTWARE_RESET: 79281a0a8bcSBenoît Thébaudeau if (val & SDHCI_RESET_DATA) 79381a0a8bcSBenoît Thébaudeau new_val = readl(host->ioaddr + SDHCI_HOST_CONTROL); 79481a0a8bcSBenoît Thébaudeau break; 79595f25efeSWolfram Sang } 79695f25efeSWolfram Sang esdhc_clrset_le(host, 0xff, val, reg); 797913413c3SShawn Guo 79881a0a8bcSBenoît Thébaudeau if (reg == SDHCI_SOFTWARE_RESET) { 79981a0a8bcSBenoît Thébaudeau if (val & SDHCI_RESET_ALL) { 800913413c3SShawn Guo /* 80181a0a8bcSBenoît Thébaudeau * The esdhc has a design violation to SDHC spec which 80281a0a8bcSBenoît Thébaudeau * tells that software reset should not affect card 80381a0a8bcSBenoît Thébaudeau * detection circuit. But esdhc clears its SYSCTL 80481a0a8bcSBenoît Thébaudeau * register bits [0..2] during the software reset. This 80581a0a8bcSBenoît Thébaudeau * will stop those clocks that card detection circuit 80681a0a8bcSBenoît Thébaudeau * relies on. To work around it, we turn the clocks on 80781a0a8bcSBenoît Thébaudeau * back to keep card detection circuit functional. 808913413c3SShawn Guo */ 809913413c3SShawn Guo esdhc_clrset_le(host, 0x7, 0x7, ESDHC_SYSTEM_CONTROL); 81058c8c4fbSShawn Guo /* 81158c8c4fbSShawn Guo * The reset on usdhc fails to clear MIX_CTRL register. 81258c8c4fbSShawn Guo * Do it manually here. 81358c8c4fbSShawn Guo */ 814de5bdbffSDong Aisheng if (esdhc_is_usdhc(imx_data)) { 81581a0a8bcSBenoît Thébaudeau /* 81681a0a8bcSBenoît Thébaudeau * the tuning bits should be kept during reset 81781a0a8bcSBenoît Thébaudeau */ 818d131a71cSDong Aisheng new_val = readl(host->ioaddr + ESDHC_MIX_CTRL); 819d131a71cSDong Aisheng writel(new_val & ESDHC_MIX_CTRL_TUNING_MASK, 820d131a71cSDong Aisheng host->ioaddr + ESDHC_MIX_CTRL); 821de5bdbffSDong Aisheng imx_data->is_ddr = 0; 822de5bdbffSDong Aisheng } 82381a0a8bcSBenoît Thébaudeau } else if (val & SDHCI_RESET_DATA) { 82481a0a8bcSBenoît Thébaudeau /* 82581a0a8bcSBenoît Thébaudeau * The eSDHC DAT line software reset clears at least the 82681a0a8bcSBenoît Thébaudeau * data transfer width on i.MX25, so make sure that the 82781a0a8bcSBenoît Thébaudeau * Host Control register is unaffected. 82881a0a8bcSBenoît Thébaudeau */ 82981a0a8bcSBenoît Thébaudeau esdhc_clrset_le(host, 0xff, new_val, 83081a0a8bcSBenoît Thébaudeau SDHCI_HOST_CONTROL); 83181a0a8bcSBenoît Thébaudeau } 83258c8c4fbSShawn Guo } 83395f25efeSWolfram Sang } 83495f25efeSWolfram Sang 8350ddf03c9SLucas Stach static unsigned int esdhc_pltfm_get_max_clock(struct sdhci_host *host) 8360ddf03c9SLucas Stach { 8370ddf03c9SLucas Stach struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); 8380ddf03c9SLucas Stach 839a974862fSDong Aisheng return pltfm_host->clock; 8400ddf03c9SLucas Stach } 8410ddf03c9SLucas Stach 84295f25efeSWolfram Sang static unsigned int esdhc_pltfm_get_min_clock(struct sdhci_host *host) 84395f25efeSWolfram Sang { 84495f25efeSWolfram Sang struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); 84595f25efeSWolfram Sang 846a974862fSDong Aisheng return pltfm_host->clock / 256 / 16; 84795f25efeSWolfram Sang } 84895f25efeSWolfram Sang 8498ba9580aSLucas Stach static inline void esdhc_pltfm_set_clock(struct sdhci_host *host, 8508ba9580aSLucas Stach unsigned int clock) 8518ba9580aSLucas Stach { 8528ba9580aSLucas Stach struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); 853070e6d3fSJisheng Zhang struct pltfm_imx_data *imx_data = sdhci_pltfm_priv(pltfm_host); 854a974862fSDong Aisheng unsigned int host_clock = pltfm_host->clock; 8555143c953SBenoît Thébaudeau int ddr_pre_div = imx_data->is_ddr ? 2 : 1; 8565143c953SBenoît Thébaudeau int pre_div = 1; 857d31fc00aSDong Aisheng int div = 1; 858f581e909SHaibo Chen int ret; 859fed2f6e2SDong Aisheng u32 temp, val; 8608ba9580aSLucas Stach 8619d61c009SShawn Guo if (esdhc_is_usdhc(imx_data)) { 862fed2f6e2SDong Aisheng val = readl(host->ioaddr + ESDHC_VENDOR_SPEC); 863fed2f6e2SDong Aisheng writel(val & ~ESDHC_VENDOR_SPEC_FRC_SDCLK_ON, 864fed2f6e2SDong Aisheng host->ioaddr + ESDHC_VENDOR_SPEC); 865f581e909SHaibo Chen esdhc_wait_for_card_clock_gate_off(host); 866fed2f6e2SDong Aisheng } 86773e736f8SStefan Agner 86873e736f8SStefan Agner if (clock == 0) { 86973e736f8SStefan Agner host->mmc->actual_clock = 0; 870373073efSRussell King return; 871fed2f6e2SDong Aisheng } 872d31fc00aSDong Aisheng 873499ed50fSBenoît Thébaudeau /* For i.MX53 eSDHCv3, SYSCTL.SDCLKFS may not be set to 0. */ 874499ed50fSBenoît Thébaudeau if (is_imx53_esdhc(imx_data)) { 875499ed50fSBenoît Thébaudeau /* 876499ed50fSBenoît Thébaudeau * According to the i.MX53 reference manual, if DLLCTRL[10] can 877499ed50fSBenoît Thébaudeau * be set, then the controller is eSDHCv3, else it is eSDHCv2. 878499ed50fSBenoît Thébaudeau */ 879499ed50fSBenoît Thébaudeau val = readl(host->ioaddr + ESDHC_DLL_CTRL); 880499ed50fSBenoît Thébaudeau writel(val | BIT(10), host->ioaddr + ESDHC_DLL_CTRL); 881499ed50fSBenoît Thébaudeau temp = readl(host->ioaddr + ESDHC_DLL_CTRL); 882499ed50fSBenoît Thébaudeau writel(val, host->ioaddr + ESDHC_DLL_CTRL); 883499ed50fSBenoît Thébaudeau if (temp & BIT(10)) 884499ed50fSBenoît Thébaudeau pre_div = 2; 885499ed50fSBenoît Thébaudeau } 886499ed50fSBenoît Thébaudeau 887d31fc00aSDong Aisheng temp = sdhci_readl(host, ESDHC_SYSTEM_CONTROL); 888d31fc00aSDong Aisheng temp &= ~(ESDHC_CLOCK_IPGEN | ESDHC_CLOCK_HCKEN | ESDHC_CLOCK_PEREN 889d31fc00aSDong Aisheng | ESDHC_CLOCK_MASK); 890d31fc00aSDong Aisheng sdhci_writel(host, temp, ESDHC_SYSTEM_CONTROL); 891d31fc00aSDong Aisheng 892af6a50d4SBOUGH CHEN if (imx_data->socdata->flags & ESDHC_FLAG_ERR010450) { 893af6a50d4SBOUGH CHEN unsigned int max_clock; 894af6a50d4SBOUGH CHEN 895af6a50d4SBOUGH CHEN max_clock = imx_data->is_ddr ? 45000000 : 150000000; 896af6a50d4SBOUGH CHEN 897af6a50d4SBOUGH CHEN clock = min(clock, max_clock); 898af6a50d4SBOUGH CHEN } 899af6a50d4SBOUGH CHEN 9005143c953SBenoît Thébaudeau while (host_clock / (16 * pre_div * ddr_pre_div) > clock && 9015143c953SBenoît Thébaudeau pre_div < 256) 902d31fc00aSDong Aisheng pre_div *= 2; 903d31fc00aSDong Aisheng 9045143c953SBenoît Thébaudeau while (host_clock / (div * pre_div * ddr_pre_div) > clock && div < 16) 905d31fc00aSDong Aisheng div++; 906d31fc00aSDong Aisheng 9075143c953SBenoît Thébaudeau host->mmc->actual_clock = host_clock / (div * pre_div * ddr_pre_div); 908d31fc00aSDong Aisheng dev_dbg(mmc_dev(host->mmc), "desired SD clock: %d, actual: %d\n", 909e76b8559SDong Aisheng clock, host->mmc->actual_clock); 910d31fc00aSDong Aisheng 911d31fc00aSDong Aisheng pre_div >>= 1; 912d31fc00aSDong Aisheng div--; 913d31fc00aSDong Aisheng 914d31fc00aSDong Aisheng temp = sdhci_readl(host, ESDHC_SYSTEM_CONTROL); 915d31fc00aSDong Aisheng temp |= (ESDHC_CLOCK_IPGEN | ESDHC_CLOCK_HCKEN | ESDHC_CLOCK_PEREN 916d31fc00aSDong Aisheng | (div << ESDHC_DIVIDER_SHIFT) 917d31fc00aSDong Aisheng | (pre_div << ESDHC_PREDIV_SHIFT)); 918d31fc00aSDong Aisheng sdhci_writel(host, temp, ESDHC_SYSTEM_CONTROL); 919fed2f6e2SDong Aisheng 920f581e909SHaibo Chen /* need to wait the bit 3 of the PRSSTAT to be set, make sure card clock is stable */ 921f581e909SHaibo Chen ret = readl_poll_timeout(host->ioaddr + ESDHC_PRSSTAT, temp, 922f581e909SHaibo Chen (temp & ESDHC_CLOCK_STABLE), 2, 100); 923f581e909SHaibo Chen if (ret == -ETIMEDOUT) 924f581e909SHaibo Chen dev_warn(mmc_dev(host->mmc), "card clock still not stable in 100us!.\n"); 925f581e909SHaibo Chen 9269d61c009SShawn Guo if (esdhc_is_usdhc(imx_data)) { 927fed2f6e2SDong Aisheng val = readl(host->ioaddr + ESDHC_VENDOR_SPEC); 928fed2f6e2SDong Aisheng writel(val | ESDHC_VENDOR_SPEC_FRC_SDCLK_ON, 929fed2f6e2SDong Aisheng host->ioaddr + ESDHC_VENDOR_SPEC); 930fed2f6e2SDong Aisheng } 931fed2f6e2SDong Aisheng 9328ba9580aSLucas Stach } 9338ba9580aSLucas Stach 934913413c3SShawn Guo static unsigned int esdhc_pltfm_get_ro(struct sdhci_host *host) 935913413c3SShawn Guo { 936842afc02SShawn Guo struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); 937070e6d3fSJisheng Zhang struct pltfm_imx_data *imx_data = sdhci_pltfm_priv(pltfm_host); 938842afc02SShawn Guo struct esdhc_platform_data *boarddata = &imx_data->boarddata; 939913413c3SShawn Guo 940913413c3SShawn Guo switch (boarddata->wp_type) { 941913413c3SShawn Guo case ESDHC_WP_GPIO: 942fbe5fdd1SShawn Guo return mmc_gpio_get_ro(host->mmc); 943913413c3SShawn Guo case ESDHC_WP_CONTROLLER: 944913413c3SShawn Guo return !(readl(host->ioaddr + SDHCI_PRESENT_STATE) & 945913413c3SShawn Guo SDHCI_WRITE_PROTECT); 946913413c3SShawn Guo case ESDHC_WP_NONE: 947913413c3SShawn Guo break; 948913413c3SShawn Guo } 949913413c3SShawn Guo 950913413c3SShawn Guo return -ENOSYS; 951913413c3SShawn Guo } 952913413c3SShawn Guo 9532317f56cSRussell King static void esdhc_pltfm_set_bus_width(struct sdhci_host *host, int width) 954af51079eSSascha Hauer { 955af51079eSSascha Hauer u32 ctrl; 956af51079eSSascha Hauer 957af51079eSSascha Hauer switch (width) { 958af51079eSSascha Hauer case MMC_BUS_WIDTH_8: 959af51079eSSascha Hauer ctrl = ESDHC_CTRL_8BITBUS; 960af51079eSSascha Hauer break; 961af51079eSSascha Hauer case MMC_BUS_WIDTH_4: 962af51079eSSascha Hauer ctrl = ESDHC_CTRL_4BITBUS; 963af51079eSSascha Hauer break; 964af51079eSSascha Hauer default: 965af51079eSSascha Hauer ctrl = 0; 966af51079eSSascha Hauer break; 967af51079eSSascha Hauer } 968af51079eSSascha Hauer 969af51079eSSascha Hauer esdhc_clrset_le(host, ESDHC_CTRL_BUSWIDTH_MASK, ctrl, 970af51079eSSascha Hauer SDHCI_HOST_CONTROL); 971af51079eSSascha Hauer } 972af51079eSSascha Hauer 973de3e1dd0SBOUGH CHEN static int usdhc_execute_tuning(struct mmc_host *mmc, u32 opcode) 974de3e1dd0SBOUGH CHEN { 975de3e1dd0SBOUGH CHEN struct sdhci_host *host = mmc_priv(mmc); 976de3e1dd0SBOUGH CHEN 977de3e1dd0SBOUGH CHEN /* 978de3e1dd0SBOUGH CHEN * i.MX uSDHC internally already uses a fixed optimized timing for 979de3e1dd0SBOUGH CHEN * DDR50, normally does not require tuning for DDR50 mode. 980de3e1dd0SBOUGH CHEN */ 981de3e1dd0SBOUGH CHEN if (host->timing == MMC_TIMING_UHS_DDR50) 982de3e1dd0SBOUGH CHEN return 0; 983de3e1dd0SBOUGH CHEN 984de3e1dd0SBOUGH CHEN return sdhci_execute_tuning(mmc, opcode); 985de3e1dd0SBOUGH CHEN } 986de3e1dd0SBOUGH CHEN 9870322191eSDong Aisheng static void esdhc_prepare_tuning(struct sdhci_host *host, u32 val) 9880322191eSDong Aisheng { 9890322191eSDong Aisheng u32 reg; 9900322191eSDong Aisheng 9910322191eSDong Aisheng /* FIXME: delay a bit for card to be ready for next tuning due to errors */ 9920322191eSDong Aisheng mdelay(1); 9930322191eSDong Aisheng 9940322191eSDong Aisheng reg = readl(host->ioaddr + ESDHC_MIX_CTRL); 9950322191eSDong Aisheng reg |= ESDHC_MIX_CTRL_EXE_TUNE | ESDHC_MIX_CTRL_SMPCLK_SEL | 9960322191eSDong Aisheng ESDHC_MIX_CTRL_FBCLK_SEL; 9970322191eSDong Aisheng writel(reg, host->ioaddr + ESDHC_MIX_CTRL); 9980322191eSDong Aisheng writel(val << 8, host->ioaddr + ESDHC_TUNE_CTRL_STATUS); 9990322191eSDong Aisheng dev_dbg(mmc_dev(host->mmc), 1000d04f8d5bSBenoît Thébaudeau "tuning with delay 0x%x ESDHC_TUNE_CTRL_STATUS 0x%x\n", 10010322191eSDong Aisheng val, readl(host->ioaddr + ESDHC_TUNE_CTRL_STATUS)); 10020322191eSDong Aisheng } 10030322191eSDong Aisheng 10040322191eSDong Aisheng static void esdhc_post_tuning(struct sdhci_host *host) 10050322191eSDong Aisheng { 10060322191eSDong Aisheng u32 reg; 10070322191eSDong Aisheng 10080322191eSDong Aisheng reg = readl(host->ioaddr + ESDHC_MIX_CTRL); 10090322191eSDong Aisheng reg &= ~ESDHC_MIX_CTRL_EXE_TUNE; 1010da0295ffSDong Aisheng reg |= ESDHC_MIX_CTRL_AUTO_TUNE_EN; 10110322191eSDong Aisheng writel(reg, host->ioaddr + ESDHC_MIX_CTRL); 10120322191eSDong Aisheng } 10130322191eSDong Aisheng 10140322191eSDong Aisheng static int esdhc_executing_tuning(struct sdhci_host *host, u32 opcode) 10150322191eSDong Aisheng { 10160322191eSDong Aisheng int min, max, avg, ret; 10170322191eSDong Aisheng 10180322191eSDong Aisheng /* find the mininum delay first which can pass tuning */ 10190322191eSDong Aisheng min = ESDHC_TUNE_CTRL_MIN; 10200322191eSDong Aisheng while (min < ESDHC_TUNE_CTRL_MAX) { 10210322191eSDong Aisheng esdhc_prepare_tuning(host, min); 10229979dbe5SChaotian Jing if (!mmc_send_tuning(host->mmc, opcode, NULL)) 10230322191eSDong Aisheng break; 10240322191eSDong Aisheng min += ESDHC_TUNE_CTRL_STEP; 10250322191eSDong Aisheng } 10260322191eSDong Aisheng 10270322191eSDong Aisheng /* find the maxinum delay which can not pass tuning */ 10280322191eSDong Aisheng max = min + ESDHC_TUNE_CTRL_STEP; 10290322191eSDong Aisheng while (max < ESDHC_TUNE_CTRL_MAX) { 10300322191eSDong Aisheng esdhc_prepare_tuning(host, max); 10319979dbe5SChaotian Jing if (mmc_send_tuning(host->mmc, opcode, NULL)) { 10320322191eSDong Aisheng max -= ESDHC_TUNE_CTRL_STEP; 10330322191eSDong Aisheng break; 10340322191eSDong Aisheng } 10350322191eSDong Aisheng max += ESDHC_TUNE_CTRL_STEP; 10360322191eSDong Aisheng } 10370322191eSDong Aisheng 10380322191eSDong Aisheng /* use average delay to get the best timing */ 10390322191eSDong Aisheng avg = (min + max) / 2; 10400322191eSDong Aisheng esdhc_prepare_tuning(host, avg); 10419979dbe5SChaotian Jing ret = mmc_send_tuning(host->mmc, opcode, NULL); 10420322191eSDong Aisheng esdhc_post_tuning(host); 10430322191eSDong Aisheng 1044d04f8d5bSBenoît Thébaudeau dev_dbg(mmc_dev(host->mmc), "tuning %s at 0x%x ret %d\n", 10450322191eSDong Aisheng ret ? "failed" : "passed", avg, ret); 10460322191eSDong Aisheng 10470322191eSDong Aisheng return ret; 10480322191eSDong Aisheng } 10490322191eSDong Aisheng 1050029e2476SBOUGH CHEN static void esdhc_hs400_enhanced_strobe(struct mmc_host *mmc, struct mmc_ios *ios) 1051029e2476SBOUGH CHEN { 1052029e2476SBOUGH CHEN struct sdhci_host *host = mmc_priv(mmc); 1053029e2476SBOUGH CHEN u32 m; 1054029e2476SBOUGH CHEN 1055029e2476SBOUGH CHEN m = readl(host->ioaddr + ESDHC_MIX_CTRL); 1056029e2476SBOUGH CHEN if (ios->enhanced_strobe) 1057029e2476SBOUGH CHEN m |= ESDHC_MIX_CTRL_HS400_ES_EN; 1058029e2476SBOUGH CHEN else 1059029e2476SBOUGH CHEN m &= ~ESDHC_MIX_CTRL_HS400_ES_EN; 1060029e2476SBOUGH CHEN writel(m, host->ioaddr + ESDHC_MIX_CTRL); 1061029e2476SBOUGH CHEN } 1062029e2476SBOUGH CHEN 1063ad93220dSDong Aisheng static int esdhc_change_pinstate(struct sdhci_host *host, 1064ad93220dSDong Aisheng unsigned int uhs) 1065ad93220dSDong Aisheng { 1066ad93220dSDong Aisheng struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); 1067070e6d3fSJisheng Zhang struct pltfm_imx_data *imx_data = sdhci_pltfm_priv(pltfm_host); 1068ad93220dSDong Aisheng struct pinctrl_state *pinctrl; 1069ad93220dSDong Aisheng 1070ad93220dSDong Aisheng dev_dbg(mmc_dev(host->mmc), "change pinctrl state for uhs %d\n", uhs); 1071ad93220dSDong Aisheng 1072ad93220dSDong Aisheng if (IS_ERR(imx_data->pinctrl) || 1073ad93220dSDong Aisheng IS_ERR(imx_data->pins_100mhz) || 1074ad93220dSDong Aisheng IS_ERR(imx_data->pins_200mhz)) 1075ad93220dSDong Aisheng return -EINVAL; 1076ad93220dSDong Aisheng 1077ad93220dSDong Aisheng switch (uhs) { 1078ad93220dSDong Aisheng case MMC_TIMING_UHS_SDR50: 10799f327845SHaibo Chen case MMC_TIMING_UHS_DDR50: 1080ad93220dSDong Aisheng pinctrl = imx_data->pins_100mhz; 1081ad93220dSDong Aisheng break; 1082ad93220dSDong Aisheng case MMC_TIMING_UHS_SDR104: 1083429a5b45SDong Aisheng case MMC_TIMING_MMC_HS200: 108428b07674SHaibo Chen case MMC_TIMING_MMC_HS400: 1085ad93220dSDong Aisheng pinctrl = imx_data->pins_200mhz; 1086ad93220dSDong Aisheng break; 1087ad93220dSDong Aisheng default: 1088ad93220dSDong Aisheng /* back to default state for other legacy timing */ 10892480b720SUlf Hansson return pinctrl_select_default_state(mmc_dev(host->mmc)); 1090ad93220dSDong Aisheng } 1091ad93220dSDong Aisheng 1092ad93220dSDong Aisheng return pinctrl_select_state(imx_data->pinctrl, pinctrl); 1093ad93220dSDong Aisheng } 1094ad93220dSDong Aisheng 109528b07674SHaibo Chen /* 1096d04f8d5bSBenoît Thébaudeau * For HS400 eMMC, there is a data_strobe line. This signal is generated 109728b07674SHaibo Chen * by the device and used for data output and CRC status response output 109828b07674SHaibo Chen * in HS400 mode. The frequency of this signal follows the frequency of 1099d04f8d5bSBenoît Thébaudeau * CLK generated by host. The host receives the data which is aligned to the 110028b07674SHaibo Chen * edge of data_strobe line. Due to the time delay between CLK line and 110128b07674SHaibo Chen * data_strobe line, if the delay time is larger than one clock cycle, 1102d04f8d5bSBenoît Thébaudeau * then CLK and data_strobe line will be misaligned, read error shows up. 110328b07674SHaibo Chen */ 110428b07674SHaibo Chen static void esdhc_set_strobe_dll(struct sdhci_host *host) 110528b07674SHaibo Chen { 11065bd2acdcSHaibo Chen struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); 11075bd2acdcSHaibo Chen struct pltfm_imx_data *imx_data = sdhci_pltfm_priv(pltfm_host); 11085bd2acdcSHaibo Chen u32 strobe_delay; 110928b07674SHaibo Chen u32 v; 1110373e800bSHaibo Chen int ret; 111128b07674SHaibo Chen 11127ac6da26SDong Aisheng /* disable clock before enabling strobe dll */ 11137ac6da26SDong Aisheng writel(readl(host->ioaddr + ESDHC_VENDOR_SPEC) & 11147ac6da26SDong Aisheng ~ESDHC_VENDOR_SPEC_FRC_SDCLK_ON, 11157ac6da26SDong Aisheng host->ioaddr + ESDHC_VENDOR_SPEC); 1116f581e909SHaibo Chen esdhc_wait_for_card_clock_gate_off(host); 11177ac6da26SDong Aisheng 111828b07674SHaibo Chen /* force a reset on strobe dll */ 111928b07674SHaibo Chen writel(ESDHC_STROBE_DLL_CTRL_RESET, 112028b07674SHaibo Chen host->ioaddr + ESDHC_STROBE_DLL_CTRL); 11212eaf5a53SBOUGH CHEN /* clear the reset bit on strobe dll before any setting */ 11222eaf5a53SBOUGH CHEN writel(0, host->ioaddr + ESDHC_STROBE_DLL_CTRL); 11232eaf5a53SBOUGH CHEN 112428b07674SHaibo Chen /* 112528b07674SHaibo Chen * enable strobe dll ctrl and adjust the delay target 112628b07674SHaibo Chen * for the uSDHC loopback read clock 112728b07674SHaibo Chen */ 11285bd2acdcSHaibo Chen if (imx_data->boarddata.strobe_dll_delay_target) 11295bd2acdcSHaibo Chen strobe_delay = imx_data->boarddata.strobe_dll_delay_target; 11305bd2acdcSHaibo Chen else 11315bd2acdcSHaibo Chen strobe_delay = ESDHC_STROBE_DLL_CTRL_SLV_DLY_TARGET_DEFAULT; 113228b07674SHaibo Chen v = ESDHC_STROBE_DLL_CTRL_ENABLE | 11332eaf5a53SBOUGH CHEN ESDHC_STROBE_DLL_CTRL_SLV_UPDATE_INT_DEFAULT | 11345bd2acdcSHaibo Chen (strobe_delay << ESDHC_STROBE_DLL_CTRL_SLV_DLY_TARGET_SHIFT); 113528b07674SHaibo Chen writel(v, host->ioaddr + ESDHC_STROBE_DLL_CTRL); 1136373e800bSHaibo Chen 1137373e800bSHaibo Chen /* wait max 50us to get the REF/SLV lock */ 1138373e800bSHaibo Chen ret = readl_poll_timeout(host->ioaddr + ESDHC_STROBE_DLL_STATUS, v, 1139373e800bSHaibo Chen ((v & ESDHC_STROBE_DLL_STS_REF_LOCK) && (v & ESDHC_STROBE_DLL_STS_SLV_LOCK)), 1, 50); 1140373e800bSHaibo Chen if (ret == -ETIMEDOUT) 114128b07674SHaibo Chen dev_warn(mmc_dev(host->mmc), 1142373e800bSHaibo Chen "warning! HS400 strobe DLL status REF/SLV not lock in 50us, STROBE DLL status is %x!\n", v); 114328b07674SHaibo Chen } 114428b07674SHaibo Chen 1145d9370424SHaibo Chen static void esdhc_reset_tuning(struct sdhci_host *host) 1146d9370424SHaibo Chen { 1147d9370424SHaibo Chen struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); 1148d9370424SHaibo Chen struct pltfm_imx_data *imx_data = sdhci_pltfm_priv(pltfm_host); 1149d9370424SHaibo Chen u32 ctrl; 1150d9370424SHaibo Chen 1151d04f8d5bSBenoît Thébaudeau /* Reset the tuning circuit */ 1152d9370424SHaibo Chen if (esdhc_is_usdhc(imx_data)) { 1153d9370424SHaibo Chen if (imx_data->socdata->flags & ESDHC_FLAG_MAN_TUNING) { 1154d9370424SHaibo Chen ctrl = readl(host->ioaddr + ESDHC_MIX_CTRL); 1155d9370424SHaibo Chen ctrl &= ~ESDHC_MIX_CTRL_SMPCLK_SEL; 1156d9370424SHaibo Chen ctrl &= ~ESDHC_MIX_CTRL_FBCLK_SEL; 1157d9370424SHaibo Chen writel(ctrl, host->ioaddr + ESDHC_MIX_CTRL); 1158d9370424SHaibo Chen writel(0, host->ioaddr + ESDHC_TUNE_CTRL_STATUS); 1159d9370424SHaibo Chen } else if (imx_data->socdata->flags & ESDHC_FLAG_STD_TUNING) { 1160869f8a69SAdrian Hunter ctrl = readl(host->ioaddr + SDHCI_AUTO_CMD_STATUS); 1161d9370424SHaibo Chen ctrl &= ~ESDHC_MIX_CTRL_SMPCLK_SEL; 1162869f8a69SAdrian Hunter writel(ctrl, host->ioaddr + SDHCI_AUTO_CMD_STATUS); 1163d9370424SHaibo Chen } 1164d9370424SHaibo Chen } 1165d9370424SHaibo Chen } 1166d9370424SHaibo Chen 1167850a29b8SRussell King static void esdhc_set_uhs_signaling(struct sdhci_host *host, unsigned timing) 1168ad93220dSDong Aisheng { 116928b07674SHaibo Chen u32 m; 1170ad93220dSDong Aisheng struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); 1171070e6d3fSJisheng Zhang struct pltfm_imx_data *imx_data = sdhci_pltfm_priv(pltfm_host); 1172602519b2SDong Aisheng struct esdhc_platform_data *boarddata = &imx_data->boarddata; 1173ad93220dSDong Aisheng 117428b07674SHaibo Chen /* disable ddr mode and disable HS400 mode */ 117528b07674SHaibo Chen m = readl(host->ioaddr + ESDHC_MIX_CTRL); 117628b07674SHaibo Chen m &= ~(ESDHC_MIX_CTRL_DDREN | ESDHC_MIX_CTRL_HS400_EN); 117728b07674SHaibo Chen imx_data->is_ddr = 0; 117828b07674SHaibo Chen 1179850a29b8SRussell King switch (timing) { 1180ad93220dSDong Aisheng case MMC_TIMING_UHS_SDR12: 1181ad93220dSDong Aisheng case MMC_TIMING_UHS_SDR25: 1182ad93220dSDong Aisheng case MMC_TIMING_UHS_SDR50: 1183ad93220dSDong Aisheng case MMC_TIMING_UHS_SDR104: 1184de0a0decSBOUGH CHEN case MMC_TIMING_MMC_HS: 1185429a5b45SDong Aisheng case MMC_TIMING_MMC_HS200: 118628b07674SHaibo Chen writel(m, host->ioaddr + ESDHC_MIX_CTRL); 1187ad93220dSDong Aisheng break; 1188ad93220dSDong Aisheng case MMC_TIMING_UHS_DDR50: 118969f5bf38SAisheng Dong case MMC_TIMING_MMC_DDR52: 119028b07674SHaibo Chen m |= ESDHC_MIX_CTRL_DDREN; 119128b07674SHaibo Chen writel(m, host->ioaddr + ESDHC_MIX_CTRL); 1192de5bdbffSDong Aisheng imx_data->is_ddr = 1; 1193602519b2SDong Aisheng if (boarddata->delay_line) { 1194602519b2SDong Aisheng u32 v; 1195602519b2SDong Aisheng v = boarddata->delay_line << 1196602519b2SDong Aisheng ESDHC_DLL_OVERRIDE_VAL_SHIFT | 1197602519b2SDong Aisheng (1 << ESDHC_DLL_OVERRIDE_EN_SHIFT); 1198602519b2SDong Aisheng if (is_imx53_esdhc(imx_data)) 1199602519b2SDong Aisheng v <<= 1; 1200602519b2SDong Aisheng writel(v, host->ioaddr + ESDHC_DLL_CTRL); 1201602519b2SDong Aisheng } 1202ad93220dSDong Aisheng break; 120328b07674SHaibo Chen case MMC_TIMING_MMC_HS400: 120428b07674SHaibo Chen m |= ESDHC_MIX_CTRL_DDREN | ESDHC_MIX_CTRL_HS400_EN; 120528b07674SHaibo Chen writel(m, host->ioaddr + ESDHC_MIX_CTRL); 120628b07674SHaibo Chen imx_data->is_ddr = 1; 12077ac6da26SDong Aisheng /* update clock after enable DDR for strobe DLL lock */ 12087ac6da26SDong Aisheng host->ops->set_clock(host, host->clock); 120928b07674SHaibo Chen esdhc_set_strobe_dll(host); 121028b07674SHaibo Chen break; 1211d9370424SHaibo Chen case MMC_TIMING_LEGACY: 1212d9370424SHaibo Chen default: 1213d9370424SHaibo Chen esdhc_reset_tuning(host); 1214d9370424SHaibo Chen break; 1215ad93220dSDong Aisheng } 1216ad93220dSDong Aisheng 1217850a29b8SRussell King esdhc_change_pinstate(host, timing); 1218ad93220dSDong Aisheng } 1219ad93220dSDong Aisheng 12200718e59aSRussell King static void esdhc_reset(struct sdhci_host *host, u8 mask) 12210718e59aSRussell King { 12220718e59aSRussell King sdhci_reset(host, mask); 12230718e59aSRussell King 12240718e59aSRussell King sdhci_writel(host, host->ier, SDHCI_INT_ENABLE); 12250718e59aSRussell King sdhci_writel(host, host->ier, SDHCI_SIGNAL_ENABLE); 12260718e59aSRussell King } 12270718e59aSRussell King 122810fd0ad9SAisheng Dong static unsigned int esdhc_get_max_timeout_count(struct sdhci_host *host) 122910fd0ad9SAisheng Dong { 123010fd0ad9SAisheng Dong struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); 1231070e6d3fSJisheng Zhang struct pltfm_imx_data *imx_data = sdhci_pltfm_priv(pltfm_host); 123210fd0ad9SAisheng Dong 1233d04f8d5bSBenoît Thébaudeau /* Doc Erratum: the uSDHC actual maximum timeout count is 1 << 29 */ 12342fb0b02bSHaibo Chen return esdhc_is_usdhc(imx_data) ? 1 << 29 : 1 << 27; 123510fd0ad9SAisheng Dong } 123610fd0ad9SAisheng Dong 1237e33eb8e2SAisheng Dong static void esdhc_set_timeout(struct sdhci_host *host, struct mmc_command *cmd) 1238e33eb8e2SAisheng Dong { 1239e33eb8e2SAisheng Dong struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); 1240070e6d3fSJisheng Zhang struct pltfm_imx_data *imx_data = sdhci_pltfm_priv(pltfm_host); 1241e33eb8e2SAisheng Dong 1242e33eb8e2SAisheng Dong /* use maximum timeout counter */ 1243a215186dSHaibo Chen esdhc_clrset_le(host, ESDHC_SYS_CTRL_DTOCV_MASK, 1244a215186dSHaibo Chen esdhc_is_usdhc(imx_data) ? 0xF : 0xE, 1245e33eb8e2SAisheng Dong SDHCI_TIMEOUT_CONTROL); 1246e33eb8e2SAisheng Dong } 1247e33eb8e2SAisheng Dong 1248bb6e3581SBOUGH CHEN static u32 esdhc_cqhci_irq(struct sdhci_host *host, u32 intmask) 1249bb6e3581SBOUGH CHEN { 1250bb6e3581SBOUGH CHEN int cmd_error = 0; 1251bb6e3581SBOUGH CHEN int data_error = 0; 1252bb6e3581SBOUGH CHEN 1253bb6e3581SBOUGH CHEN if (!sdhci_cqe_irq(host, intmask, &cmd_error, &data_error)) 1254bb6e3581SBOUGH CHEN return intmask; 1255bb6e3581SBOUGH CHEN 1256bb6e3581SBOUGH CHEN cqhci_irq(host->mmc, intmask, cmd_error, data_error); 1257bb6e3581SBOUGH CHEN 1258bb6e3581SBOUGH CHEN return 0; 1259bb6e3581SBOUGH CHEN } 1260bb6e3581SBOUGH CHEN 12616e9fd28eSDong Aisheng static struct sdhci_ops sdhci_esdhc_ops = { 1262e149860dSRichard Zhu .read_l = esdhc_readl_le, 12630c6d49ceSWolfram Sang .read_w = esdhc_readw_le, 126477da3da0SAaron Brice .read_b = esdhc_readb_le, 1265e149860dSRichard Zhu .write_l = esdhc_writel_le, 12660c6d49ceSWolfram Sang .write_w = esdhc_writew_le, 12670c6d49ceSWolfram Sang .write_b = esdhc_writeb_le, 12688ba9580aSLucas Stach .set_clock = esdhc_pltfm_set_clock, 12690ddf03c9SLucas Stach .get_max_clock = esdhc_pltfm_get_max_clock, 12700c6d49ceSWolfram Sang .get_min_clock = esdhc_pltfm_get_min_clock, 127110fd0ad9SAisheng Dong .get_max_timeout_count = esdhc_get_max_timeout_count, 1272913413c3SShawn Guo .get_ro = esdhc_pltfm_get_ro, 1273e33eb8e2SAisheng Dong .set_timeout = esdhc_set_timeout, 12742317f56cSRussell King .set_bus_width = esdhc_pltfm_set_bus_width, 1275ad93220dSDong Aisheng .set_uhs_signaling = esdhc_set_uhs_signaling, 12760718e59aSRussell King .reset = esdhc_reset, 1277bb6e3581SBOUGH CHEN .irq = esdhc_cqhci_irq, 12783722c74cSHaibo Chen .dump_vendor_regs = esdhc_dump_debug_regs, 12790c6d49ceSWolfram Sang }; 12800c6d49ceSWolfram Sang 12811db5eebfSLars-Peter Clausen static const struct sdhci_pltfm_data sdhci_esdhc_imx_pdata = { 128297e4ba6aSRichard Zhu .quirks = ESDHC_DEFAULT_QUIRKS | SDHCI_QUIRK_NO_HISPD_BIT 128397e4ba6aSRichard Zhu | SDHCI_QUIRK_NO_ENDATTR_IN_NOPDESC 128497e4ba6aSRichard Zhu | SDHCI_QUIRK_BROKEN_ADMA_ZEROLEN_DESC 128585d6509dSShawn Guo | SDHCI_QUIRK_BROKEN_CARD_DETECTION, 128685d6509dSShawn Guo .ops = &sdhci_esdhc_ops, 128785d6509dSShawn Guo }; 128885d6509dSShawn Guo 1289f3f5cf3dSDong Aisheng static void sdhci_esdhc_imx_hwinit(struct sdhci_host *host) 1290f3f5cf3dSDong Aisheng { 1291f3f5cf3dSDong Aisheng struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); 1292f3f5cf3dSDong Aisheng struct pltfm_imx_data *imx_data = sdhci_pltfm_priv(pltfm_host); 1293982cf37dSHaibo Chen struct cqhci_host *cq_host = host->mmc->cqe_private; 12942b16cf32SDong Aisheng int tmp; 1295f3f5cf3dSDong Aisheng 1296f3f5cf3dSDong Aisheng if (esdhc_is_usdhc(imx_data)) { 1297f3f5cf3dSDong Aisheng /* 1298f3f5cf3dSDong Aisheng * The imx6q ROM code will change the default watermark 1299f3f5cf3dSDong Aisheng * level setting to something insane. Change it back here. 1300f3f5cf3dSDong Aisheng */ 1301f3f5cf3dSDong Aisheng writel(ESDHC_WTMK_DEFAULT_VAL, host->ioaddr + ESDHC_WTMK_LVL); 1302f3f5cf3dSDong Aisheng 1303f3f5cf3dSDong Aisheng /* 1304f3f5cf3dSDong Aisheng * ROM code will change the bit burst_length_enable setting 1305d04f8d5bSBenoît Thébaudeau * to zero if this usdhc is chosen to boot system. Change 1306f3f5cf3dSDong Aisheng * it back here, otherwise it will impact the performance a 1307f3f5cf3dSDong Aisheng * lot. This bit is used to enable/disable the burst length 1308d04f8d5bSBenoît Thébaudeau * for the external AHB2AXI bridge. It's useful especially 1309f3f5cf3dSDong Aisheng * for INCR transfer because without burst length indicator, 1310f3f5cf3dSDong Aisheng * the AHB2AXI bridge does not know the burst length in 1311f3f5cf3dSDong Aisheng * advance. And without burst length indicator, AHB INCR 1312f3f5cf3dSDong Aisheng * transfer can only be converted to singles on the AXI side. 1313f3f5cf3dSDong Aisheng */ 1314f3f5cf3dSDong Aisheng writel(readl(host->ioaddr + SDHCI_HOST_CONTROL) 1315f3f5cf3dSDong Aisheng | ESDHC_BURST_LEN_EN_INCR, 1316f3f5cf3dSDong Aisheng host->ioaddr + SDHCI_HOST_CONTROL); 1317e30be063SBOUGH CHEN 1318f3f5cf3dSDong Aisheng /* 1319d04f8d5bSBenoît Thébaudeau * erratum ESDHC_FLAG_ERR004536 fix for MX6Q TO1.2 and MX6DL 1320f3f5cf3dSDong Aisheng * TO1.1, it's harmless for MX6SL 1321f3f5cf3dSDong Aisheng */ 1322e30be063SBOUGH CHEN writel(readl(host->ioaddr + 0x6c) & ~BIT(7), 1323f3f5cf3dSDong Aisheng host->ioaddr + 0x6c); 1324f3f5cf3dSDong Aisheng 1325f3f5cf3dSDong Aisheng /* disable DLL_CTRL delay line settings */ 1326f3f5cf3dSDong Aisheng writel(0x0, host->ioaddr + ESDHC_DLL_CTRL); 13272b16cf32SDong Aisheng 1328bcdb5301SBOUGH CHEN /* 1329bcdb5301SBOUGH CHEN * For the case of command with busy, if set the bit 1330bcdb5301SBOUGH CHEN * ESDHC_VEND_SPEC2_EN_BUSY_IRQ, USDHC will generate a 1331bcdb5301SBOUGH CHEN * transfer complete interrupt when busy is deasserted. 1332bcdb5301SBOUGH CHEN * When CQHCI use DCMD to send a CMD need R1b respons, 1333bcdb5301SBOUGH CHEN * CQHCI require to set ESDHC_VEND_SPEC2_EN_BUSY_IRQ, 1334bcdb5301SBOUGH CHEN * otherwise DCMD will always meet timeout waiting for 1335bcdb5301SBOUGH CHEN * hardware interrupt issue. 1336bcdb5301SBOUGH CHEN */ 1337bcdb5301SBOUGH CHEN if (imx_data->socdata->flags & ESDHC_FLAG_CQHCI) { 1338bcdb5301SBOUGH CHEN tmp = readl(host->ioaddr + ESDHC_VEND_SPEC2); 1339bcdb5301SBOUGH CHEN tmp |= ESDHC_VEND_SPEC2_EN_BUSY_IRQ; 1340bcdb5301SBOUGH CHEN writel(tmp, host->ioaddr + ESDHC_VEND_SPEC2); 1341bcdb5301SBOUGH CHEN 1342bcdb5301SBOUGH CHEN host->quirks &= ~SDHCI_QUIRK_NO_BUSY_IRQ; 1343bcdb5301SBOUGH CHEN } 1344bcdb5301SBOUGH CHEN 13452b16cf32SDong Aisheng if (imx_data->socdata->flags & ESDHC_FLAG_STD_TUNING) { 13462b16cf32SDong Aisheng tmp = readl(host->ioaddr + ESDHC_TUNING_CTRL); 13472b16cf32SDong Aisheng tmp |= ESDHC_STD_TUNING_EN | 13482b16cf32SDong Aisheng ESDHC_TUNING_START_TAP_DEFAULT; 13492b16cf32SDong Aisheng if (imx_data->boarddata.tuning_start_tap) { 13502b16cf32SDong Aisheng tmp &= ~ESDHC_TUNING_START_TAP_MASK; 13512b16cf32SDong Aisheng tmp |= imx_data->boarddata.tuning_start_tap; 13522b16cf32SDong Aisheng } 13532b16cf32SDong Aisheng 13542b16cf32SDong Aisheng if (imx_data->boarddata.tuning_step) { 13552b16cf32SDong Aisheng tmp &= ~ESDHC_TUNING_STEP_MASK; 13562b16cf32SDong Aisheng tmp |= imx_data->boarddata.tuning_step 13572b16cf32SDong Aisheng << ESDHC_TUNING_STEP_SHIFT; 13582b16cf32SDong Aisheng } 135916e40e5bSHaibo Chen 136016e40e5bSHaibo Chen /* Disable the CMD CRC check for tuning, if not, need to 136116e40e5bSHaibo Chen * add some delay after every tuning command, because 136216e40e5bSHaibo Chen * hardware standard tuning logic will directly go to next 136316e40e5bSHaibo Chen * step once it detect the CMD CRC error, will not wait for 136416e40e5bSHaibo Chen * the card side to finally send out the tuning data, trigger 136516e40e5bSHaibo Chen * the buffer read ready interrupt immediately. If usdhc send 136616e40e5bSHaibo Chen * the next tuning command some eMMC card will stuck, can't 136716e40e5bSHaibo Chen * response, block the tuning procedure or the first command 136816e40e5bSHaibo Chen * after the whole tuning procedure always can't get any response. 136916e40e5bSHaibo Chen */ 137016e40e5bSHaibo Chen tmp |= ESDHC_TUNING_CMD_CRC_CHECK_DISABLE; 13712b16cf32SDong Aisheng writel(tmp, host->ioaddr + ESDHC_TUNING_CTRL); 1372a98c557eSBOUGH CHEN } else if (imx_data->socdata->flags & ESDHC_FLAG_MAN_TUNING) { 1373a98c557eSBOUGH CHEN /* 1374a98c557eSBOUGH CHEN * ESDHC_STD_TUNING_EN may be configed in bootloader 1375a98c557eSBOUGH CHEN * or ROM code, so clear this bit here to make sure 1376a98c557eSBOUGH CHEN * the manual tuning can work. 1377a98c557eSBOUGH CHEN */ 1378a98c557eSBOUGH CHEN tmp = readl(host->ioaddr + ESDHC_TUNING_CTRL); 1379a98c557eSBOUGH CHEN tmp &= ~ESDHC_STD_TUNING_EN; 1380a98c557eSBOUGH CHEN writel(tmp, host->ioaddr + ESDHC_TUNING_CTRL); 13812b16cf32SDong Aisheng } 1382982cf37dSHaibo Chen 1383982cf37dSHaibo Chen /* 1384982cf37dSHaibo Chen * On i.MX8MM, we are running Dual Linux OS, with 1st Linux using SD Card 1385982cf37dSHaibo Chen * as rootfs storage, 2nd Linux using eMMC as rootfs storage. We let the 1386982cf37dSHaibo Chen * the 1st linux configure power/clock for the 2nd Linux. 1387982cf37dSHaibo Chen * 1388982cf37dSHaibo Chen * When the 2nd Linux is booting into rootfs stage, we let the 1st Linux 1389982cf37dSHaibo Chen * to destroy the 2nd linux, then restart the 2nd linux, we met SDHCI dump. 1390982cf37dSHaibo Chen * After we clear the pending interrupt and halt CQCTL, issue gone. 1391982cf37dSHaibo Chen */ 1392982cf37dSHaibo Chen if (cq_host) { 1393982cf37dSHaibo Chen tmp = cqhci_readl(cq_host, CQHCI_IS); 1394982cf37dSHaibo Chen cqhci_writel(cq_host, tmp, CQHCI_IS); 1395982cf37dSHaibo Chen cqhci_writel(cq_host, CQHCI_HALT, CQHCI_CTL); 1396982cf37dSHaibo Chen } 1397f3f5cf3dSDong Aisheng } 1398f3f5cf3dSDong Aisheng } 1399f3f5cf3dSDong Aisheng 1400bb6e3581SBOUGH CHEN static void esdhc_cqe_enable(struct mmc_host *mmc) 1401bb6e3581SBOUGH CHEN { 1402bb6e3581SBOUGH CHEN struct sdhci_host *host = mmc_priv(mmc); 140385236d2bSBOUGH CHEN struct cqhci_host *cq_host = mmc->cqe_private; 1404bb6e3581SBOUGH CHEN u32 reg; 1405bb6e3581SBOUGH CHEN u16 mode; 1406bb6e3581SBOUGH CHEN int count = 10; 1407bb6e3581SBOUGH CHEN 1408bb6e3581SBOUGH CHEN /* 1409bb6e3581SBOUGH CHEN * CQE gets stuck if it sees Buffer Read Enable bit set, which can be 1410bb6e3581SBOUGH CHEN * the case after tuning, so ensure the buffer is drained. 1411bb6e3581SBOUGH CHEN */ 1412bb6e3581SBOUGH CHEN reg = sdhci_readl(host, SDHCI_PRESENT_STATE); 1413bb6e3581SBOUGH CHEN while (reg & SDHCI_DATA_AVAILABLE) { 1414bb6e3581SBOUGH CHEN sdhci_readl(host, SDHCI_BUFFER); 1415bb6e3581SBOUGH CHEN reg = sdhci_readl(host, SDHCI_PRESENT_STATE); 1416bb6e3581SBOUGH CHEN if (count-- == 0) { 1417bb6e3581SBOUGH CHEN dev_warn(mmc_dev(host->mmc), 1418bb6e3581SBOUGH CHEN "CQE may get stuck because the Buffer Read Enable bit is set\n"); 1419bb6e3581SBOUGH CHEN break; 1420bb6e3581SBOUGH CHEN } 1421bb6e3581SBOUGH CHEN mdelay(1); 1422bb6e3581SBOUGH CHEN } 1423bb6e3581SBOUGH CHEN 1424bb6e3581SBOUGH CHEN /* 1425bb6e3581SBOUGH CHEN * Runtime resume will reset the entire host controller, which 1426bb6e3581SBOUGH CHEN * will also clear the DMAEN/BCEN of register ESDHC_MIX_CTRL. 1427bb6e3581SBOUGH CHEN * Here set DMAEN and BCEN when enable CMDQ. 1428bb6e3581SBOUGH CHEN */ 1429bb6e3581SBOUGH CHEN mode = sdhci_readw(host, SDHCI_TRANSFER_MODE); 1430bb6e3581SBOUGH CHEN if (host->flags & SDHCI_REQ_USE_DMA) 1431bb6e3581SBOUGH CHEN mode |= SDHCI_TRNS_DMA; 1432bb6e3581SBOUGH CHEN if (!(host->quirks2 & SDHCI_QUIRK2_SUPPORT_SINGLE)) 1433bb6e3581SBOUGH CHEN mode |= SDHCI_TRNS_BLK_CNT_EN; 1434bb6e3581SBOUGH CHEN sdhci_writew(host, mode, SDHCI_TRANSFER_MODE); 1435bb6e3581SBOUGH CHEN 143685236d2bSBOUGH CHEN /* 143785236d2bSBOUGH CHEN * Though Runtime resume reset the entire host controller, 143885236d2bSBOUGH CHEN * but do not impact the CQHCI side, need to clear the 143985236d2bSBOUGH CHEN * HALT bit, avoid CQHCI stuck in the first request when 144085236d2bSBOUGH CHEN * system resume back. 144185236d2bSBOUGH CHEN */ 144285236d2bSBOUGH CHEN cqhci_writel(cq_host, 0, CQHCI_CTL); 144385236d2bSBOUGH CHEN if (cqhci_readl(cq_host, CQHCI_CTL) && CQHCI_HALT) 144485236d2bSBOUGH CHEN dev_err(mmc_dev(host->mmc), 144585236d2bSBOUGH CHEN "failed to exit halt state when enable CQE\n"); 144685236d2bSBOUGH CHEN 144785236d2bSBOUGH CHEN 1448bb6e3581SBOUGH CHEN sdhci_cqe_enable(mmc); 1449bb6e3581SBOUGH CHEN } 1450bb6e3581SBOUGH CHEN 1451bb6e3581SBOUGH CHEN static void esdhc_sdhci_dumpregs(struct mmc_host *mmc) 1452bb6e3581SBOUGH CHEN { 1453bb6e3581SBOUGH CHEN sdhci_dumpregs(mmc_priv(mmc)); 1454bb6e3581SBOUGH CHEN } 1455bb6e3581SBOUGH CHEN 1456bb6e3581SBOUGH CHEN static const struct cqhci_host_ops esdhc_cqhci_ops = { 1457bb6e3581SBOUGH CHEN .enable = esdhc_cqe_enable, 1458bb6e3581SBOUGH CHEN .disable = sdhci_cqe_disable, 1459bb6e3581SBOUGH CHEN .dumpregs = esdhc_sdhci_dumpregs, 1460bb6e3581SBOUGH CHEN }; 1461bb6e3581SBOUGH CHEN 1462abfafc2dSShawn Guo #ifdef CONFIG_OF 1463c3be1efdSBill Pemberton static int 1464abfafc2dSShawn Guo sdhci_esdhc_imx_probe_dt(struct platform_device *pdev, 146507bf2b54SSascha Hauer struct sdhci_host *host, 146691fa4252SDong Aisheng struct pltfm_imx_data *imx_data) 1467abfafc2dSShawn Guo { 1468abfafc2dSShawn Guo struct device_node *np = pdev->dev.of_node; 146991fa4252SDong Aisheng struct esdhc_platform_data *boarddata = &imx_data->boarddata; 14704800e87aSDong Aisheng int ret; 1471abfafc2dSShawn Guo 1472abfafc2dSShawn Guo if (of_get_property(np, "fsl,wp-controller", NULL)) 1473abfafc2dSShawn Guo boarddata->wp_type = ESDHC_WP_CONTROLLER; 1474abfafc2dSShawn Guo 147574ff81e1SLinus Walleij /* 147674ff81e1SLinus Walleij * If we have this property, then activate WP check. 147774ff81e1SLinus Walleij * Retrieveing and requesting the actual WP GPIO will happen 147874ff81e1SLinus Walleij * in the call to mmc_of_parse(). 147974ff81e1SLinus Walleij */ 148074ff81e1SLinus Walleij if (of_property_read_bool(np, "wp-gpios")) 1481abfafc2dSShawn Guo boarddata->wp_type = ESDHC_WP_GPIO; 1482abfafc2dSShawn Guo 1483d407e30bSHaibo Chen of_property_read_u32(np, "fsl,tuning-step", &boarddata->tuning_step); 1484d87fc966SDong Aisheng of_property_read_u32(np, "fsl,tuning-start-tap", 1485d87fc966SDong Aisheng &boarddata->tuning_start_tap); 1486d407e30bSHaibo Chen 14875bd2acdcSHaibo Chen of_property_read_u32(np, "fsl,strobe-dll-delay-target", 14885bd2acdcSHaibo Chen &boarddata->strobe_dll_delay_target); 1489ad93220dSDong Aisheng if (of_find_property(np, "no-1-8-v", NULL)) 149086f495c5SStefan Agner host->quirks2 |= SDHCI_QUIRK2_NO_1_8_V; 1491ad93220dSDong Aisheng 1492602519b2SDong Aisheng if (of_property_read_u32(np, "fsl,delay-line", &boarddata->delay_line)) 1493602519b2SDong Aisheng boarddata->delay_line = 0; 1494602519b2SDong Aisheng 149507bf2b54SSascha Hauer mmc_of_parse_voltage(np, &host->ocr_mask); 149607bf2b54SSascha Hauer 14972480b720SUlf Hansson if (esdhc_is_usdhc(imx_data)) { 149891fa4252SDong Aisheng imx_data->pins_100mhz = pinctrl_lookup_state(imx_data->pinctrl, 149991fa4252SDong Aisheng ESDHC_PINCTRL_STATE_100MHZ); 150091fa4252SDong Aisheng imx_data->pins_200mhz = pinctrl_lookup_state(imx_data->pinctrl, 150191fa4252SDong Aisheng ESDHC_PINCTRL_STATE_200MHZ); 150291fa4252SDong Aisheng } 150391fa4252SDong Aisheng 150415064119SFabio Estevam /* call to generic mmc_of_parse to support additional capabilities */ 15054800e87aSDong Aisheng ret = mmc_of_parse(host->mmc); 15064800e87aSDong Aisheng if (ret) 15074800e87aSDong Aisheng return ret; 15084800e87aSDong Aisheng 1509287980e4SArnd Bergmann if (mmc_gpio_get_cd(host->mmc) >= 0) 15104800e87aSDong Aisheng host->quirks &= ~SDHCI_QUIRK_BROKEN_CARD_DETECTION; 15114800e87aSDong Aisheng 15124800e87aSDong Aisheng return 0; 1513abfafc2dSShawn Guo } 1514abfafc2dSShawn Guo #else 1515abfafc2dSShawn Guo static inline int 1516abfafc2dSShawn Guo sdhci_esdhc_imx_probe_dt(struct platform_device *pdev, 151707bf2b54SSascha Hauer struct sdhci_host *host, 151891fa4252SDong Aisheng struct pltfm_imx_data *imx_data) 1519abfafc2dSShawn Guo { 1520abfafc2dSShawn Guo return -ENODEV; 1521abfafc2dSShawn Guo } 1522abfafc2dSShawn Guo #endif 1523abfafc2dSShawn Guo 152491fa4252SDong Aisheng static int sdhci_esdhc_imx_probe_nondt(struct platform_device *pdev, 152591fa4252SDong Aisheng struct sdhci_host *host, 152691fa4252SDong Aisheng struct pltfm_imx_data *imx_data) 152791fa4252SDong Aisheng { 152891fa4252SDong Aisheng struct esdhc_platform_data *boarddata = &imx_data->boarddata; 152991fa4252SDong Aisheng int err; 153091fa4252SDong Aisheng 153191fa4252SDong Aisheng if (!host->mmc->parent->platform_data) { 153291fa4252SDong Aisheng dev_err(mmc_dev(host->mmc), "no board data!\n"); 153391fa4252SDong Aisheng return -EINVAL; 153491fa4252SDong Aisheng } 153591fa4252SDong Aisheng 153691fa4252SDong Aisheng imx_data->boarddata = *((struct esdhc_platform_data *) 153791fa4252SDong Aisheng host->mmc->parent->platform_data); 153891fa4252SDong Aisheng /* write_protect */ 153991fa4252SDong Aisheng if (boarddata->wp_type == ESDHC_WP_GPIO) { 15409073d10bSMichał Mirosław host->mmc->caps2 |= MMC_CAP2_RO_ACTIVE_HIGH; 15419073d10bSMichał Mirosław 1542d0052ad9SMichał Mirosław err = mmc_gpiod_request_ro(host->mmc, "wp", 0, 0); 154391fa4252SDong Aisheng if (err) { 154491fa4252SDong Aisheng dev_err(mmc_dev(host->mmc), 154591fa4252SDong Aisheng "failed to request write-protect gpio!\n"); 154691fa4252SDong Aisheng return err; 154791fa4252SDong Aisheng } 154891fa4252SDong Aisheng } 154991fa4252SDong Aisheng 155091fa4252SDong Aisheng /* card_detect */ 155191fa4252SDong Aisheng switch (boarddata->cd_type) { 155291fa4252SDong Aisheng case ESDHC_CD_GPIO: 1553d0052ad9SMichał Mirosław err = mmc_gpiod_request_cd(host->mmc, "cd", 0, false, 0); 155491fa4252SDong Aisheng if (err) { 155591fa4252SDong Aisheng dev_err(mmc_dev(host->mmc), 155691fa4252SDong Aisheng "failed to request card-detect gpio!\n"); 155791fa4252SDong Aisheng return err; 155891fa4252SDong Aisheng } 1559*df561f66SGustavo A. R. Silva fallthrough; 156091fa4252SDong Aisheng 156191fa4252SDong Aisheng case ESDHC_CD_CONTROLLER: 156291fa4252SDong Aisheng /* we have a working card_detect back */ 156391fa4252SDong Aisheng host->quirks &= ~SDHCI_QUIRK_BROKEN_CARD_DETECTION; 156491fa4252SDong Aisheng break; 156591fa4252SDong Aisheng 156691fa4252SDong Aisheng case ESDHC_CD_PERMANENT: 156791fa4252SDong Aisheng host->mmc->caps |= MMC_CAP_NONREMOVABLE; 156891fa4252SDong Aisheng break; 156991fa4252SDong Aisheng 157091fa4252SDong Aisheng case ESDHC_CD_NONE: 157191fa4252SDong Aisheng break; 157291fa4252SDong Aisheng } 157391fa4252SDong Aisheng 157491fa4252SDong Aisheng switch (boarddata->max_bus_width) { 157591fa4252SDong Aisheng case 8: 157691fa4252SDong Aisheng host->mmc->caps |= MMC_CAP_8_BIT_DATA | MMC_CAP_4_BIT_DATA; 157791fa4252SDong Aisheng break; 157891fa4252SDong Aisheng case 4: 157991fa4252SDong Aisheng host->mmc->caps |= MMC_CAP_4_BIT_DATA; 158091fa4252SDong Aisheng break; 158191fa4252SDong Aisheng case 1: 158291fa4252SDong Aisheng default: 158391fa4252SDong Aisheng host->quirks |= SDHCI_QUIRK_FORCE_1_BIT_DATA; 158491fa4252SDong Aisheng break; 158591fa4252SDong Aisheng } 158691fa4252SDong Aisheng 158791fa4252SDong Aisheng return 0; 158891fa4252SDong Aisheng } 158991fa4252SDong Aisheng 1590c3be1efdSBill Pemberton static int sdhci_esdhc_imx_probe(struct platform_device *pdev) 159195f25efeSWolfram Sang { 1592abfafc2dSShawn Guo const struct of_device_id *of_id = 1593abfafc2dSShawn Guo of_match_device(imx_esdhc_dt_ids, &pdev->dev); 159485d6509dSShawn Guo struct sdhci_pltfm_host *pltfm_host; 159585d6509dSShawn Guo struct sdhci_host *host; 1596bb6e3581SBOUGH CHEN struct cqhci_host *cq_host; 15970c6d49ceSWolfram Sang int err; 1598e149860dSRichard Zhu struct pltfm_imx_data *imx_data; 159995f25efeSWolfram Sang 1600070e6d3fSJisheng Zhang host = sdhci_pltfm_init(pdev, &sdhci_esdhc_imx_pdata, 1601070e6d3fSJisheng Zhang sizeof(*imx_data)); 160285d6509dSShawn Guo if (IS_ERR(host)) 160385d6509dSShawn Guo return PTR_ERR(host); 160485d6509dSShawn Guo 160585d6509dSShawn Guo pltfm_host = sdhci_priv(host); 160685d6509dSShawn Guo 1607070e6d3fSJisheng Zhang imx_data = sdhci_pltfm_priv(pltfm_host); 160857ed3314SShawn Guo 1609f47c4bbfSShawn Guo imx_data->socdata = of_id ? of_id->data : (struct esdhc_soc_data *) 16103770ee8fSShawn Guo pdev->id_entry->driver_data; 161185d6509dSShawn Guo 16121c4989b0SBOUGH CHEN if (imx_data->socdata->flags & ESDHC_FLAG_PMQOS) 1613d1b98305SRafael J. Wysocki cpu_latency_qos_add_request(&imx_data->pm_qos_req, 0); 16141c4989b0SBOUGH CHEN 161552dac615SSascha Hauer imx_data->clk_ipg = devm_clk_get(&pdev->dev, "ipg"); 161652dac615SSascha Hauer if (IS_ERR(imx_data->clk_ipg)) { 161752dac615SSascha Hauer err = PTR_ERR(imx_data->clk_ipg); 1618e3af31c6SShawn Guo goto free_sdhci; 161995f25efeSWolfram Sang } 162052dac615SSascha Hauer 162152dac615SSascha Hauer imx_data->clk_ahb = devm_clk_get(&pdev->dev, "ahb"); 162252dac615SSascha Hauer if (IS_ERR(imx_data->clk_ahb)) { 162352dac615SSascha Hauer err = PTR_ERR(imx_data->clk_ahb); 1624e3af31c6SShawn Guo goto free_sdhci; 162552dac615SSascha Hauer } 162652dac615SSascha Hauer 162752dac615SSascha Hauer imx_data->clk_per = devm_clk_get(&pdev->dev, "per"); 162852dac615SSascha Hauer if (IS_ERR(imx_data->clk_per)) { 162952dac615SSascha Hauer err = PTR_ERR(imx_data->clk_per); 1630e3af31c6SShawn Guo goto free_sdhci; 163152dac615SSascha Hauer } 163252dac615SSascha Hauer 163352dac615SSascha Hauer pltfm_host->clk = imx_data->clk_per; 1634a974862fSDong Aisheng pltfm_host->clock = clk_get_rate(pltfm_host->clk); 163517b1eb7fSFabio Estevam err = clk_prepare_enable(imx_data->clk_per); 163617b1eb7fSFabio Estevam if (err) 163717b1eb7fSFabio Estevam goto free_sdhci; 163817b1eb7fSFabio Estevam err = clk_prepare_enable(imx_data->clk_ipg); 163917b1eb7fSFabio Estevam if (err) 164017b1eb7fSFabio Estevam goto disable_per_clk; 164117b1eb7fSFabio Estevam err = clk_prepare_enable(imx_data->clk_ahb); 164217b1eb7fSFabio Estevam if (err) 164317b1eb7fSFabio Estevam goto disable_ipg_clk; 164495f25efeSWolfram Sang 1645ad93220dSDong Aisheng imx_data->pinctrl = devm_pinctrl_get(&pdev->dev); 1646e62d8b8fSDong Aisheng if (IS_ERR(imx_data->pinctrl)) { 1647e62d8b8fSDong Aisheng err = PTR_ERR(imx_data->pinctrl); 1648b62eee9fSHaibo Chen dev_warn(mmc_dev(host->mmc), "could not get pinctrl\n"); 1649e62d8b8fSDong Aisheng } 1650e62d8b8fSDong Aisheng 165169ed60e0SDong Aisheng if (esdhc_is_usdhc(imx_data)) { 165269ed60e0SDong Aisheng host->quirks2 |= SDHCI_QUIRK2_PRESET_VALUE_BROKEN; 165309c8192bSStefan Agner host->mmc->caps |= MMC_CAP_1_8V_DDR | MMC_CAP_3_3V_DDR; 1654f6140462SHaibo Chen 1655f6140462SHaibo Chen /* GPIO CD can be set as a wakeup source */ 1656f6140462SHaibo Chen host->mmc->caps |= MMC_CAP_CD_WAKE; 1657f6140462SHaibo Chen 16584245afffSDong Aisheng if (!(imx_data->socdata->flags & ESDHC_FLAG_HS200)) 16594245afffSDong Aisheng host->quirks2 |= SDHCI_QUIRK2_BROKEN_HS200; 1660a75dcbf4SDong Aisheng 1661a75dcbf4SDong Aisheng /* clear tuning bits in case ROM has set it already */ 1662a75dcbf4SDong Aisheng writel(0x0, host->ioaddr + ESDHC_MIX_CTRL); 1663869f8a69SAdrian Hunter writel(0x0, host->ioaddr + SDHCI_AUTO_CMD_STATUS); 1664a75dcbf4SDong Aisheng writel(0x0, host->ioaddr + ESDHC_TUNE_CTRL_STATUS); 1665de3e1dd0SBOUGH CHEN 1666de3e1dd0SBOUGH CHEN /* 1667de3e1dd0SBOUGH CHEN * Link usdhc specific mmc_host_ops execute_tuning function, 1668de3e1dd0SBOUGH CHEN * to replace the standard one in sdhci_ops. 1669de3e1dd0SBOUGH CHEN */ 1670de3e1dd0SBOUGH CHEN host->mmc_host_ops.execute_tuning = usdhc_execute_tuning; 167169ed60e0SDong Aisheng } 1672f750ba9bSShawn Guo 16736e9fd28eSDong Aisheng if (imx_data->socdata->flags & ESDHC_FLAG_MAN_TUNING) 16746e9fd28eSDong Aisheng sdhci_esdhc_ops.platform_execute_tuning = 16756e9fd28eSDong Aisheng esdhc_executing_tuning; 16768b2bb0adSDong Aisheng 167718094430SDong Aisheng if (imx_data->socdata->flags & ESDHC_FLAG_ERR004536) 167818094430SDong Aisheng host->quirks |= SDHCI_QUIRK_BROKEN_ADMA; 167918094430SDong Aisheng 168028b07674SHaibo Chen if (imx_data->socdata->flags & ESDHC_FLAG_HS400) 168128b07674SHaibo Chen host->quirks2 |= SDHCI_QUIRK2_CAPS_BIT63_FOR_HS400; 168228b07674SHaibo Chen 168374898cbcSHaibo Chen if (imx_data->socdata->flags & ESDHC_FLAG_BROKEN_AUTO_CMD23) 168474898cbcSHaibo Chen host->quirks2 |= SDHCI_QUIRK2_ACMD23_BROKEN; 168574898cbcSHaibo Chen 1686029e2476SBOUGH CHEN if (imx_data->socdata->flags & ESDHC_FLAG_HS400_ES) { 1687029e2476SBOUGH CHEN host->mmc->caps2 |= MMC_CAP2_HS400_ES; 1688029e2476SBOUGH CHEN host->mmc_host_ops.hs400_enhanced_strobe = 1689029e2476SBOUGH CHEN esdhc_hs400_enhanced_strobe; 1690029e2476SBOUGH CHEN } 1691029e2476SBOUGH CHEN 1692bb6e3581SBOUGH CHEN if (imx_data->socdata->flags & ESDHC_FLAG_CQHCI) { 1693bcdb5301SBOUGH CHEN host->mmc->caps2 |= MMC_CAP2_CQE | MMC_CAP2_CQE_DCMD; 1694bb6e3581SBOUGH CHEN cq_host = devm_kzalloc(&pdev->dev, sizeof(*cq_host), GFP_KERNEL); 16959a633f3bSWei Yongjun if (!cq_host) { 16969a633f3bSWei Yongjun err = -ENOMEM; 1697bb6e3581SBOUGH CHEN goto disable_ahb_clk; 1698bb6e3581SBOUGH CHEN } 1699bb6e3581SBOUGH CHEN 1700bb6e3581SBOUGH CHEN cq_host->mmio = host->ioaddr + ESDHC_CQHCI_ADDR_OFFSET; 1701bb6e3581SBOUGH CHEN cq_host->ops = &esdhc_cqhci_ops; 1702bb6e3581SBOUGH CHEN 1703bb6e3581SBOUGH CHEN err = cqhci_init(cq_host, host->mmc, false); 1704bb6e3581SBOUGH CHEN if (err) 1705bb6e3581SBOUGH CHEN goto disable_ahb_clk; 1706bb6e3581SBOUGH CHEN } 1707bb6e3581SBOUGH CHEN 170891fa4252SDong Aisheng if (of_id) 170991fa4252SDong Aisheng err = sdhci_esdhc_imx_probe_dt(pdev, host, imx_data); 171091fa4252SDong Aisheng else 171191fa4252SDong Aisheng err = sdhci_esdhc_imx_probe_nondt(pdev, host, imx_data); 171291fa4252SDong Aisheng if (err) 171317b1eb7fSFabio Estevam goto disable_ahb_clk; 1714ad93220dSDong Aisheng 1715f3f5cf3dSDong Aisheng sdhci_esdhc_imx_hwinit(host); 1716f3f5cf3dSDong Aisheng 171785d6509dSShawn Guo err = sdhci_add_host(host); 171885d6509dSShawn Guo if (err) 171917b1eb7fSFabio Estevam goto disable_ahb_clk; 172085d6509dSShawn Guo 172189d7e5c1SDong Aisheng pm_runtime_set_active(&pdev->dev); 172289d7e5c1SDong Aisheng pm_runtime_set_autosuspend_delay(&pdev->dev, 50); 172389d7e5c1SDong Aisheng pm_runtime_use_autosuspend(&pdev->dev); 172489d7e5c1SDong Aisheng pm_suspend_ignore_children(&pdev->dev, 1); 172577903c01SUlf Hansson pm_runtime_enable(&pdev->dev); 172689d7e5c1SDong Aisheng 17277e29c306SWolfram Sang return 0; 17287e29c306SWolfram Sang 172917b1eb7fSFabio Estevam disable_ahb_clk: 173052dac615SSascha Hauer clk_disable_unprepare(imx_data->clk_ahb); 173117b1eb7fSFabio Estevam disable_ipg_clk: 173217b1eb7fSFabio Estevam clk_disable_unprepare(imx_data->clk_ipg); 173317b1eb7fSFabio Estevam disable_per_clk: 173417b1eb7fSFabio Estevam clk_disable_unprepare(imx_data->clk_per); 1735e3af31c6SShawn Guo free_sdhci: 17361c4989b0SBOUGH CHEN if (imx_data->socdata->flags & ESDHC_FLAG_PMQOS) 1737d1b98305SRafael J. Wysocki cpu_latency_qos_remove_request(&imx_data->pm_qos_req); 173885d6509dSShawn Guo sdhci_pltfm_free(pdev); 173985d6509dSShawn Guo return err; 174095f25efeSWolfram Sang } 174195f25efeSWolfram Sang 17426e0ee714SBill Pemberton static int sdhci_esdhc_imx_remove(struct platform_device *pdev) 174395f25efeSWolfram Sang { 174485d6509dSShawn Guo struct sdhci_host *host = platform_get_drvdata(pdev); 174595f25efeSWolfram Sang struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); 1746070e6d3fSJisheng Zhang struct pltfm_imx_data *imx_data = sdhci_pltfm_priv(pltfm_host); 174785d6509dSShawn Guo int dead = (readl(host->ioaddr + SDHCI_INT_STATUS) == 0xffffffff); 174885d6509dSShawn Guo 17490b414368SUlf Hansson pm_runtime_get_sync(&pdev->dev); 17500b414368SUlf Hansson pm_runtime_disable(&pdev->dev); 17510b414368SUlf Hansson pm_runtime_put_noidle(&pdev->dev); 17520b414368SUlf Hansson 175385d6509dSShawn Guo sdhci_remove_host(host, dead); 17540c6d49ceSWolfram Sang 175552dac615SSascha Hauer clk_disable_unprepare(imx_data->clk_per); 175652dac615SSascha Hauer clk_disable_unprepare(imx_data->clk_ipg); 175752dac615SSascha Hauer clk_disable_unprepare(imx_data->clk_ahb); 175852dac615SSascha Hauer 17591c4989b0SBOUGH CHEN if (imx_data->socdata->flags & ESDHC_FLAG_PMQOS) 1760d1b98305SRafael J. Wysocki cpu_latency_qos_remove_request(&imx_data->pm_qos_req); 17611c4989b0SBOUGH CHEN 176285d6509dSShawn Guo sdhci_pltfm_free(pdev); 176385d6509dSShawn Guo 176485d6509dSShawn Guo return 0; 176595f25efeSWolfram Sang } 176695f25efeSWolfram Sang 17672788ed42SUlf Hansson #ifdef CONFIG_PM_SLEEP 176804143fbaSDong Aisheng static int sdhci_esdhc_suspend(struct device *dev) 176904143fbaSDong Aisheng { 17703e3274abSUlf Hansson struct sdhci_host *host = dev_get_drvdata(dev); 1771a26a4f1bSHaibo Chen struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); 1772a26a4f1bSHaibo Chen struct pltfm_imx_data *imx_data = sdhci_pltfm_priv(pltfm_host); 1773bb6e3581SBOUGH CHEN int ret; 1774bb6e3581SBOUGH CHEN 1775bb6e3581SBOUGH CHEN if (host->mmc->caps2 & MMC_CAP2_CQE) { 1776bb6e3581SBOUGH CHEN ret = cqhci_suspend(host->mmc); 1777bb6e3581SBOUGH CHEN if (ret) 1778bb6e3581SBOUGH CHEN return ret; 1779bb6e3581SBOUGH CHEN } 17803e3274abSUlf Hansson 1781a26a4f1bSHaibo Chen if ((imx_data->socdata->flags & ESDHC_FLAG_STATE_LOST_IN_LPMODE) && 1782a26a4f1bSHaibo Chen (host->tuning_mode != SDHCI_TUNING_MODE_1)) { 1783a26a4f1bSHaibo Chen mmc_retune_timer_stop(host->mmc); 1784a26a4f1bSHaibo Chen mmc_retune_needed(host->mmc); 1785a26a4f1bSHaibo Chen } 1786a26a4f1bSHaibo Chen 1787d38dcad4SAdrian Hunter if (host->tuning_mode != SDHCI_TUNING_MODE_3) 1788d38dcad4SAdrian Hunter mmc_retune_needed(host->mmc); 1789d38dcad4SAdrian Hunter 1790af8fade4SHaibo Chen ret = sdhci_suspend_host(host); 1791f6140462SHaibo Chen if (ret) 1792f6140462SHaibo Chen return ret; 1793f6140462SHaibo Chen 1794f6140462SHaibo Chen ret = pinctrl_pm_select_sleep_state(dev); 1795f6140462SHaibo Chen if (ret) 1796f6140462SHaibo Chen return ret; 1797f6140462SHaibo Chen 1798f6140462SHaibo Chen ret = mmc_gpio_set_cd_wake(host->mmc, true); 1799af8fade4SHaibo Chen 1800af8fade4SHaibo Chen return ret; 180104143fbaSDong Aisheng } 180204143fbaSDong Aisheng 180304143fbaSDong Aisheng static int sdhci_esdhc_resume(struct device *dev) 180404143fbaSDong Aisheng { 1805cc17e129SDong Aisheng struct sdhci_host *host = dev_get_drvdata(dev); 1806bb6e3581SBOUGH CHEN int ret; 1807cc17e129SDong Aisheng 1808af8fade4SHaibo Chen ret = pinctrl_pm_select_default_state(dev); 1809af8fade4SHaibo Chen if (ret) 1810af8fade4SHaibo Chen return ret; 1811af8fade4SHaibo Chen 181219dbfdd3SDong Aisheng /* re-initialize hw state in case it's lost in low power mode */ 181319dbfdd3SDong Aisheng sdhci_esdhc_imx_hwinit(host); 1814cc17e129SDong Aisheng 1815bb6e3581SBOUGH CHEN ret = sdhci_resume_host(host); 1816bb6e3581SBOUGH CHEN if (ret) 1817bb6e3581SBOUGH CHEN return ret; 1818bb6e3581SBOUGH CHEN 1819bb6e3581SBOUGH CHEN if (host->mmc->caps2 & MMC_CAP2_CQE) 1820bb6e3581SBOUGH CHEN ret = cqhci_resume(host->mmc); 1821bb6e3581SBOUGH CHEN 1822f6140462SHaibo Chen if (!ret) 1823f6140462SHaibo Chen ret = mmc_gpio_set_cd_wake(host->mmc, false); 1824f6140462SHaibo Chen 1825bb6e3581SBOUGH CHEN return ret; 182604143fbaSDong Aisheng } 18272788ed42SUlf Hansson #endif 182804143fbaSDong Aisheng 18292788ed42SUlf Hansson #ifdef CONFIG_PM 183089d7e5c1SDong Aisheng static int sdhci_esdhc_runtime_suspend(struct device *dev) 183189d7e5c1SDong Aisheng { 183289d7e5c1SDong Aisheng struct sdhci_host *host = dev_get_drvdata(dev); 183389d7e5c1SDong Aisheng struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); 1834070e6d3fSJisheng Zhang struct pltfm_imx_data *imx_data = sdhci_pltfm_priv(pltfm_host); 183589d7e5c1SDong Aisheng int ret; 183689d7e5c1SDong Aisheng 1837bb6e3581SBOUGH CHEN if (host->mmc->caps2 & MMC_CAP2_CQE) { 1838bb6e3581SBOUGH CHEN ret = cqhci_suspend(host->mmc); 1839bb6e3581SBOUGH CHEN if (ret) 1840bb6e3581SBOUGH CHEN return ret; 1841bb6e3581SBOUGH CHEN } 1842bb6e3581SBOUGH CHEN 184389d7e5c1SDong Aisheng ret = sdhci_runtime_suspend_host(host); 1844371d39faSMichael Trimarchi if (ret) 1845371d39faSMichael Trimarchi return ret; 184689d7e5c1SDong Aisheng 1847d38dcad4SAdrian Hunter if (host->tuning_mode != SDHCI_TUNING_MODE_3) 1848d38dcad4SAdrian Hunter mmc_retune_needed(host->mmc); 1849d38dcad4SAdrian Hunter 18503602785bSMichael Trimarchi imx_data->actual_clock = host->mmc->actual_clock; 18513602785bSMichael Trimarchi esdhc_pltfm_set_clock(host, 0); 185289d7e5c1SDong Aisheng clk_disable_unprepare(imx_data->clk_per); 185389d7e5c1SDong Aisheng clk_disable_unprepare(imx_data->clk_ipg); 185489d7e5c1SDong Aisheng clk_disable_unprepare(imx_data->clk_ahb); 185589d7e5c1SDong Aisheng 18561c4989b0SBOUGH CHEN if (imx_data->socdata->flags & ESDHC_FLAG_PMQOS) 1857d1b98305SRafael J. Wysocki cpu_latency_qos_remove_request(&imx_data->pm_qos_req); 18581c4989b0SBOUGH CHEN 185989d7e5c1SDong Aisheng return ret; 186089d7e5c1SDong Aisheng } 186189d7e5c1SDong Aisheng 186289d7e5c1SDong Aisheng static int sdhci_esdhc_runtime_resume(struct device *dev) 186389d7e5c1SDong Aisheng { 186489d7e5c1SDong Aisheng struct sdhci_host *host = dev_get_drvdata(dev); 186589d7e5c1SDong Aisheng struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); 1866070e6d3fSJisheng Zhang struct pltfm_imx_data *imx_data = sdhci_pltfm_priv(pltfm_host); 186717b1eb7fSFabio Estevam int err; 186889d7e5c1SDong Aisheng 18691c4989b0SBOUGH CHEN if (imx_data->socdata->flags & ESDHC_FLAG_PMQOS) 1870d1b98305SRafael J. Wysocki cpu_latency_qos_add_request(&imx_data->pm_qos_req, 0); 18711c4989b0SBOUGH CHEN 18725c11f1ffSHaibo Chen if (imx_data->socdata->flags & ESDHC_FLAG_CLK_RATE_LOST_IN_PM_RUNTIME) 18735c11f1ffSHaibo Chen clk_set_rate(imx_data->clk_per, pltfm_host->clock); 18745c11f1ffSHaibo Chen 1875a0ad3087SMichael Trimarchi err = clk_prepare_enable(imx_data->clk_ahb); 1876a0ad3087SMichael Trimarchi if (err) 18771c4989b0SBOUGH CHEN goto remove_pm_qos_request; 1878a0ad3087SMichael Trimarchi 187917b1eb7fSFabio Estevam err = clk_prepare_enable(imx_data->clk_per); 188017b1eb7fSFabio Estevam if (err) 1881a0ad3087SMichael Trimarchi goto disable_ahb_clk; 1882af5d2b7bSUlf Hansson 188317b1eb7fSFabio Estevam err = clk_prepare_enable(imx_data->clk_ipg); 188417b1eb7fSFabio Estevam if (err) 188517b1eb7fSFabio Estevam goto disable_per_clk; 1886af5d2b7bSUlf Hansson 18873602785bSMichael Trimarchi esdhc_pltfm_set_clock(host, imx_data->actual_clock); 1888a0ad3087SMichael Trimarchi 1889c6303c5dSBaolin Wang err = sdhci_runtime_resume_host(host, 0); 189017b1eb7fSFabio Estevam if (err) 1891a0ad3087SMichael Trimarchi goto disable_ipg_clk; 189289d7e5c1SDong Aisheng 1893bb6e3581SBOUGH CHEN if (host->mmc->caps2 & MMC_CAP2_CQE) 1894bb6e3581SBOUGH CHEN err = cqhci_resume(host->mmc); 1895bb6e3581SBOUGH CHEN 1896bb6e3581SBOUGH CHEN return err; 189717b1eb7fSFabio Estevam 189817b1eb7fSFabio Estevam disable_ipg_clk: 189917b1eb7fSFabio Estevam clk_disable_unprepare(imx_data->clk_ipg); 190017b1eb7fSFabio Estevam disable_per_clk: 190117b1eb7fSFabio Estevam clk_disable_unprepare(imx_data->clk_per); 1902a0ad3087SMichael Trimarchi disable_ahb_clk: 1903a0ad3087SMichael Trimarchi clk_disable_unprepare(imx_data->clk_ahb); 19041c4989b0SBOUGH CHEN remove_pm_qos_request: 19051c4989b0SBOUGH CHEN if (imx_data->socdata->flags & ESDHC_FLAG_PMQOS) 1906d1b98305SRafael J. Wysocki cpu_latency_qos_remove_request(&imx_data->pm_qos_req); 190717b1eb7fSFabio Estevam return err; 190889d7e5c1SDong Aisheng } 190989d7e5c1SDong Aisheng #endif 191089d7e5c1SDong Aisheng 191189d7e5c1SDong Aisheng static const struct dev_pm_ops sdhci_esdhc_pmops = { 191204143fbaSDong Aisheng SET_SYSTEM_SLEEP_PM_OPS(sdhci_esdhc_suspend, sdhci_esdhc_resume) 191389d7e5c1SDong Aisheng SET_RUNTIME_PM_OPS(sdhci_esdhc_runtime_suspend, 191489d7e5c1SDong Aisheng sdhci_esdhc_runtime_resume, NULL) 191589d7e5c1SDong Aisheng }; 191689d7e5c1SDong Aisheng 191785d6509dSShawn Guo static struct platform_driver sdhci_esdhc_imx_driver = { 191885d6509dSShawn Guo .driver = { 191985d6509dSShawn Guo .name = "sdhci-esdhc-imx", 1920abfafc2dSShawn Guo .of_match_table = imx_esdhc_dt_ids, 192189d7e5c1SDong Aisheng .pm = &sdhci_esdhc_pmops, 192285d6509dSShawn Guo }, 192357ed3314SShawn Guo .id_table = imx_esdhc_devtype, 192485d6509dSShawn Guo .probe = sdhci_esdhc_imx_probe, 19250433c143SBill Pemberton .remove = sdhci_esdhc_imx_remove, 192695f25efeSWolfram Sang }; 192785d6509dSShawn Guo 1928d1f81a64SAxel Lin module_platform_driver(sdhci_esdhc_imx_driver); 192985d6509dSShawn Guo 193085d6509dSShawn Guo MODULE_DESCRIPTION("SDHCI driver for Freescale i.MX eSDHC"); 1931035ff831SWolfram Sang MODULE_AUTHOR("Wolfram Sang <kernel@pengutronix.de>"); 193285d6509dSShawn Guo MODULE_LICENSE("GPL v2"); 1933